{
  "step": "registry-snapshot",
  "tool": "registry_snapshot",
  "input": {
    "detail": "full"
  },
  "isError": false,
  "error": null,
  "output": {
    "maps": [],
    "traits": {
      "Addressable": {
        "name": "Addressable",
        "version": "1.0.0",
        "description": "Canonical multi-role address trait with validation metadata, geocoding, and international formatting hooks.\nProvides a single, reusable capability for billing, shipping, warehouse, and office addresses.",
        "category": "core",
        "tags": [
          "address",
          "location",
          "validation",
          "delivery"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "AddressSummaryBadge",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "field": "default_address_role"
            }
          },
          {
            "component": "AddressCollectionPanel",
            "context": "detail",
            "position": "main",
            "priority": 60,
            "props": {
              "field": "addresses",
              "roleField": "address_roles",
              "defaultRoleField": "default_address_role",
              "roleParameter": "roles"
            }
          },
          {
            "component": "AddressEditor",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "field": "addresses",
              "roleParameter": "roles",
              "allowDynamicParameter": "allowDynamicRoles",
              "defaultRoleField": "default_address_role"
            }
          }
        ],
        "parameters": [
          {
            "name": "roles",
            "type": "string[]",
            "required": true,
            "description": "Ordered list of supported address roles (billing, shipping, warehouse, etc.).",
            "default": [
              "billing",
              "shipping"
            ],
            "validation": {
              "minItems": 1,
              "maxItems": 16,
              "uniqueItems": true,
              "items": {
                "pattern": "^[a-z0-9._-]+$",
                "minLength": 2,
                "maxLength": 32
              }
            }
          },
          {
            "name": "defaultRole",
            "type": "string",
            "required": false,
            "description": "Preferred role returned when consumers omit a role argument.",
            "validation": {
              "enumFromParameter": "roles"
            }
          },
          {
            "name": "allowDynamicRoles",
            "type": "boolean",
            "required": false,
            "description": "Allow runtime creation of roles that are not pre-declared in roles.",
            "default": false
          }
        ],
        "schema": {
          "address_roles": {
            "type": "string[]",
            "required": true,
            "description": "Ordered list of roles that currently have address entries.",
            "default": []
          },
          "default_address_role": {
            "type": "string",
            "required": false,
            "description": "Role surfaced in UI contexts when one address must be highlighted.",
            "validation": {
              "enumFromParameter": "roles"
            }
          },
          "addresses": {
            "type": "AddressableEntry[]",
            "required": false,
            "description": "Collection of { role, address, metadata } entries keyed by role.",
            "default": []
          }
        },
        "semantics": {
          "addresses": {
            "semantic_type": "location.address.collection",
            "token_mapping": "tokenMap(location.address.collection)",
            "ui_hints": {
              "component": "AddressCollection",
              "roleParameter": "roles",
              "defaultRoleField": "default_address_role"
            }
          },
          "default_address_role": {
            "semantic_type": "location.address.default_role",
            "token_mapping": "tokenMap(location.address.default_role)",
            "ui_hints": {
              "component": "AddressRoleBadge",
              "parameterSource": "defaultRole"
            }
          },
          "address_roles": {
            "semantic_type": "location.address.roles",
            "token_mapping": "tokenMap(location.address.roles)",
            "ui_hints": {
              "component": "AddressRolePills"
            }
          }
        },
        "tokens": {
          "location.address.card.bg": "var(--sys-surface-raised)",
          "location.address.card.border": "var(--sys-border-subtle)",
          "location.address.role.text": "var(--sys-text-muted)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-17",
          "owners": [
            "core@oods.systems",
            "platform@oods.systems"
          ],
          "maturity": "experimental",
          "accessibility": {
            "keyboard": "AddressEditor respects standard focus order and announces role changes.",
            "screenreader": "AddressCollection surfaces headings per role and announces validation status."
          },
          "regionsUsed": [
            "list",
            "detail",
            "form"
          ],
          "examples": [
            "User",
            "Organization"
          ],
          "references": [
            "R21.1 Canonical Model for Address/Location Systems"
          ]
        },
        "objects": [
          "Organization",
          "User"
        ],
        "source": "traits/core/Addressable.trait.yaml"
      },
      "Archivable": {
        "name": "Archivable",
        "version": "2.0.0",
        "description": "Provides archival lifecycle management with configurable retention, restoration, audit\ntracking, and compliance metadata. Archivable manages the full archive-restore-purge\nlifecycle, including soft-delete with configurable duration before hard deletion,\npartial restoration support, and per-archive compliance tagging.\n\nObjects composing Archivable can be soft-deleted (moved to an \"archived\" state with\nfull data retention), restored within a configurable window, or permanently purged\nafter the retention period expires. The trait tracks who archived the entity, why,\nand through what method (manual, automated, policy) for audit trail completeness.",
        "category": "lifecycle",
        "tags": [
          "lifecycle",
          "archival",
          "retention",
          "compliance",
          "audit",
          "soft-delete"
        ],
        "contexts": [
          "card",
          "detail",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "ArchivedRowOverlay",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "archivedField": "is_archived",
              "style": "grayed",
              "showBadge": true,
              "separateTab": true,
              "tabLabel": "Archived"
            }
          },
          {
            "component": "ArchiveSummary",
            "context": "detail",
            "position": "top",
            "priority": null,
            "props": {
              "hideWhenDefault": true,
              "archivedField": "is_archived",
              "archivedAtField": "archived_at",
              "restoredAtField": "restored_at",
              "reasonField": "archive_reason",
              "archivedByField": "archived_by",
              "metadataField": "archive_metadata",
              "retainHistoryParameter": "retainHistory",
              "restoreWindowParameter": "restoreWindowDays",
              "allowPartialRestoreParameter": "allowPartialRestore"
            }
          },
          {
            "component": "ArchivePill",
            "context": "card",
            "position": "before",
            "priority": null,
            "props": {
              "field": "is_archived",
              "archivedAtField": "archived_at",
              "hideWhenFalse": true
            }
          }
        ],
        "parameters": [
          {
            "name": "gracePeriodDays",
            "type": "number",
            "required": false,
            "description": "Number of days after archival before permanent deletion (hard-delete) occurs.",
            "default": 30,
            "validation": {
              "minimum": 0,
              "maximum": 365
            }
          },
          {
            "name": "retainHistory",
            "type": "boolean",
            "required": false,
            "description": "Whether archival retains a readable change history that can be restored.",
            "default": true
          },
          {
            "name": "restoreWindowDays",
            "type": "number",
            "required": false,
            "description": "Maximum number of days archived entities can be restored when history is retained.\nAfter this window, restoration is no longer possible even if the entity hasn't been\nhard-deleted yet.\n",
            "validation": {
              "minimum": 0,
              "maximum": 365
            }
          },
          {
            "name": "softDeleteDuration",
            "type": "number",
            "required": false,
            "description": "Days the entity remains in soft-deleted state before automatic hard deletion.\nDistinct from gracePeriodDays: gracePeriodDays is the notification/warning window,\nwhile softDeleteDuration is the total retention period. When set, a background\nprocess purges entities where (archived_at + softDeleteDuration) has passed.\n",
            "default": 90,
            "validation": {
              "minimum": 0,
              "maximum": 3650
            }
          },
          {
            "name": "allowPartialRestore",
            "type": "boolean",
            "required": false,
            "description": "When true, archived entities can be partially restored — selecting which fields\nor related data to bring back rather than restoring the entire entity. Useful for\nlarge objects where only specific sections need to be recovered (e.g., restoring\na contract's terms but not its expired billing data).\n",
            "default": false
          }
        ],
        "schema": {
          "is_archived": {
            "type": "boolean",
            "required": true,
            "description": "Flag indicating whether the entity is currently archived (soft-deleted).",
            "default": false
          },
          "archived_at": {
            "type": "datetime?",
            "required": false,
            "description": "Timestamp for when the entity entered the archived state."
          },
          "restored_at": {
            "type": "datetime?",
            "required": false,
            "description": "Timestamp for when the entity was most recently restored from an archived state."
          },
          "archive_reason": {
            "type": "string",
            "required": false,
            "description": "Human-readable narrative describing why the entity was archived.",
            "validation": {
              "maxLength": 500
            }
          },
          "archived_by": {
            "type": "string",
            "required": false,
            "description": "User ID or system identifier of the actor who archived this entity.\nSet to \"system\" for automated/policy-driven archival. Supports audit trail queries\nlike \"show all entities archived by user X\" or \"show all auto-archived entities\".\n"
          },
          "archive_metadata": {
            "type": "object",
            "required": false,
            "description": "Structured metadata about the archival action for compliance and audit purposes.\n\nProperties:\n  - method: \"manual\" | \"automated\" | \"policy\" — how the archive was triggered\n  - compliance_tags: string[] — regulatory labels (e.g., [\"GDPR\", \"SOX\", \"HIPAA\"])\n  - retention_policy_id: string — reference to the retention policy that triggered archival\n  - original_status: string — the Stateful status before archival\n  - related_entity_count: number — count of related entities also archived (cascade)\n"
          },
          "restoration_metadata": {
            "type": "object",
            "required": false,
            "description": "Metadata about the most recent restoration action.\n\nProperties:\n  - restored_by: string — user ID or \"system\"\n  - restored_fields: string[] — when partial restore, which fields were restored\n  - restoration_reason: string — why the entity was restored\n  - restored_from_snapshot: boolean — whether restored from a point-in-time snapshot\n"
          }
        },
        "semantics": {
          "is_archived": {
            "semantic_type": "status.archive.state",
            "token_mapping": "tokenMap(status.archive.*)",
            "ui_hints": {
              "component": "ArchiveBadge",
              "showIcon": true
            }
          },
          "archived_at": {
            "semantic_type": "status.archive.timestamp",
            "token_mapping": "tokenMap(status.archive.timestamp)",
            "ui_hints": {
              "component": "TimelineTimestamp"
            }
          },
          "restored_at": {
            "semantic_type": "status.archive.restore_timestamp",
            "token_mapping": "tokenMap(status.archive.restore)",
            "ui_hints": {
              "component": "TimelineTimestamp"
            }
          },
          "archive_reason": {
            "semantic_type": "status.archive.reason",
            "token_mapping": "tokenMap(status.archive.reason)",
            "ui_hints": {
              "component": "ArchiveReason",
              "maxLength": 500
            }
          },
          "archived_by": {
            "semantic_type": "status.archive.actor",
            "token_mapping": "tokenMap(status.archive.actor)",
            "ui_hints": {
              "component": "ActorLabel"
            }
          },
          "archive_metadata": {
            "semantic_type": "status.archive.compliance",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "ArchiveCompliancePanel"
            }
          },
          "restoration_metadata": {
            "semantic_type": "status.archive.restoration",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "RestorationSummary"
            }
          }
        },
        "tokens": {
          "status.archive.primary.bg": "var(--status-archive-bg)",
          "status.archive.primary.text": "var(--status-archive-text)",
          "status.archive.primary.border": "var(--sys-border-default)",
          "status.archive.timestamp.text": "var(--text-subtle)",
          "status.archive.reason.text": "var(--text-default)",
          "status.archive.reason.bg": "var(--sys-surface-neutral)",
          "status.archive.overlay.bg": "var(--sys-surface-disabled)",
          "status.archive.overlay.opacity": "0.6",
          "status.archive.actor.text": "var(--sys-text-secondary)",
          "status.archive.compliance.badge.bg": "var(--sys-status-info-surface)",
          "status.archive.compliance.badge.text": "var(--sys-status-info-text)"
        },
        "dependencies": [
          "Stateful"
        ],
        "metadata": {
          "created": "2025-10-12",
          "updated": "2026-02-28",
          "owners": [
            "lifecycle@oods.systems",
            "compliance@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "Archive/Restore actions are triggered via buttons that are keyboard-focusable and\nactivated with Enter/Space. Confirmation dialogs trap focus until dismissed.\n",
            "screenreader": "ArchiveBadge announces \"Archived\" or \"Active\" state. ArchiveSummary announces\narchive date, reason, actor, and remaining restore window. ArchivedRowOverlay\napplies aria-hidden=false to ensure archived rows remain accessible but are\nannounced as \"Archived: [entity name]\" to screen readers.\n",
            "listPresentation": "Archived items in list view are visually dimmed (opacity: 0.6) and optionally\nmoved to a separate \"Archived\" tab. Both presentations maintain keyboard\nnavigability and screen reader access.\n"
          },
          "regionsUsed": [
            "list",
            "detail",
            "card"
          ],
          "examples": [
            "Contract",
            "Product Listing",
            "User Account",
            "Subscription"
          ],
          "references": [
            "Trait Engine Spec v0.1 section 2",
            "GDPR Article 17 — Right to Erasure (soft-delete as intermediate step)"
          ]
        },
        "objects": [
          "Subscription",
          "Transaction"
        ],
        "source": "traits/lifecycle/Archivable.trait.yaml"
      },
      "Assessable": {
        "name": "Assessable",
        "version": "1.1.0",
        "description": "Records what an assessment concluded about a record — its result state — as something other than a\nverdict colour.\n\nA result is not binary. An accessibility engine returns four kinds of answer for every rule on every\npage: it found a violation, it found nothing wrong, it could not decide and a person must look, or the\nrule does not apply there. A fifth is the one engines drop: the check never ran. Lighthouse carries the\nsame shape as score display modes (binary, manual, notApplicable, error). A real capture run records\nall four axe answers — violations as items, and needs-review, passing and not-applicable as page-level\ncounts (28, 2,029 and 1,531) — and Deque warns that implementations drop the incomplete ones. That is\nwhy this is its own trait rather than a Stateful state set: it is not a lifecycle a record moves\nthrough, it is what one reading concluded, and the non-verdicts are the part most often lost.\n\nThe rule that matters is visual. A result state renders as its OWN visual family, never the severity\nfamily: never red, never green, never scored. The moment \"needs review\" looks like a failure, someone\nreports it as one; the moment \"passed\" looks like a success badge, a count of 2,029 passes reads as a\ngrade. The composer enforces it (`enforceResultStateFamily`): every StatusBadge or Badge bound to\n`result_state` carries the result tone from @oods/component-contracts, and a component that cannot\ncarry a tone is refused (OODS-V211). A spec fails if any theme scope resolves that tone to a severity\ncolour.\n\nThe field is `result_state`, not `status`, so an object can carry a lifecycle through Stateful and a\nresult through this trait without the two colliding (the Supersedable precedent). Severity is a\nseparate fact about a violation (Finding.impact) and is never folded into the result state.\n\nArtifact assessments also record measured (the measurement ran), measured_zero (it ran and found\nnone) and unknown (the historical record contains no result). A zero is evidence of measurement,\nnever a missing check. These states use the same neutral family and carry no inferred grade.\n\nNot adopted, with the reason: low-confidence (no capture artifact carries a confidence for a result; the\nConfidence-bearing trait is not authored until a screen needs it); Lighthouse's informative (it states\nno verdict and no capture record carries one); any numeric score (a score is a verdict colour in another\nform).",
        "category": "core",
        "tags": [
          "assessment",
          "result",
          "non-verdict",
          "accessibility",
          "evidence"
        ],
        "contexts": [
          "card",
          "detail",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "StatusBadge",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "statusField": "result_state",
              "domain": "result",
              "emphasis": "subtle",
              "showIcon": false
            }
          },
          {
            "component": "StatusBadge",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "statusField": "result_state",
              "domain": "result",
              "emphasis": "subtle",
              "showIcon": false
            }
          },
          {
            "component": "StatusBadge",
            "context": "detail",
            "position": "main",
            "priority": 72,
            "props": {
              "statusField": "result_state",
              "domain": "result",
              "emphasis": "subtle",
              "showIcon": false
            }
          }
        ],
        "parameters": [
          {
            "name": "recordedStates",
            "type": "string[]",
            "required": true,
            "description": "The result states the source of truth writes as items. Current capture evidence writes violations\nand needs-review items; historical counts alone never become invented findings. Artifact indices\ndeclare measured results separately from their absence.\n",
            "default": [
              "violation",
              "passed",
              "needs_review",
              "not_applicable",
              "not_measured",
              "measured",
              "measured_zero",
              "unknown"
            ]
          }
        ],
        "schema": {
          "result_state": {
            "type": "string",
            "required": true,
            "description": "What the assessment concluded for this record: violation (it measured a failure), passed (it measured\nand found none), needs_review (it could not decide — axe incomplete, Lighthouse manual), not_applicable\n(the rule does not apply here), not_measured (the check did not run). An absent value is never read as\npassed. Measured_zero means a completed measurement found none; unknown means no recorded result.\n",
            "validation": {
              "enum": [
                "violation",
                "passed",
                "needs_review",
                "not_applicable",
                "not_measured",
                "measured",
                "measured_zero",
                "unknown"
              ]
            }
          }
        },
        "semantics": {
          "result_state": {
            "semantic_type": "assessment.result.state",
            "token_mapping": "tokenMap(assessment.result.*)",
            "ui_hints": {
              "component": "StatusBadge",
              "showIcon": false
            }
          }
        },
        "tokens": {
          "assessment.result.tone": "neutral"
        },
        "dependencies": [],
        "metadata": {
          "created": "2026-09-18",
          "updated": "2026-09-20",
          "owners": [
            "core@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "keyboard": "The result state adds no interactive control; it renders as text beside the record.",
            "screenreader": "Announced as its visible wording (\"Needs review\", \"Not applicable\"), never by colour, and never as a\nstatus of the record's lifecycle.\n"
          },
          "regionsUsed": [
            "list",
            "card",
            "detail"
          ],
          "examples": [
            "Finding"
          ],
          "references": [
            "objects/provenance.v1.json#/references/ref-b9c43cb31221 — the four axe answers on run 6e435ce7, three of them as counts only",
            "https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#results-object — passes, violations, incomplete, inapplicable",
            "https://github.com/GoogleChrome/lighthouse/blob/main/docs/understanding-results.md — scoreDisplayMode"
          ]
        },
        "objects": [],
        "source": "traits/core/Assessable.trait.yaml"
      },
      "Auditable": {
        "name": "Auditable",
        "version": "1.0.0",
        "description": "Compliance-grade audit trail trait that captures state transitions with actor,\nreason, and timestamp metadata. Auditable observes Stateful transitions and\nrecords them as an append-only audit log suitable for compliance review,\ndebugging, and timeline rendering.\n\nAuditable defines the INTERFACE for audit data — the schema shape, parameters,\nand view extensions that match the existing implementation. Advanced compliance\nfeatures (crypto-shredding, KMS integration, tamper-proof hashing) are documented\nin R21.3 research and targeted for future enrichment.\n\nCore concepts:\n- Audit Log: append-only array of AuditEntry records\n- Transition Capture: from_state → to_state with timestamp, actor, and reason\n- Retention Policy: configurable retention period for log entries\n- Actor Tracking: optional actor_id capture for accountability\n- Reason Enforcement: optional requirement for transition justification",
        "category": "lifecycle",
        "tags": [
          "audit",
          "compliance",
          "trail",
          "lifecycle",
          "transition",
          "accountability"
        ],
        "contexts": [
          "detail",
          "timeline"
        ],
        "viewExtensions": [
          {
            "component": "AuditTimeline",
            "context": "timeline",
            "position": "main",
            "priority": 60,
            "props": {
              "auditLogField": "audit_log",
              "maxVisible": 7,
              "showFromState": true,
              "showActorId": true,
              "showReason": true
            }
          },
          {
            "component": "AuditSummaryCard",
            "context": "detail",
            "position": "main",
            "priority": 50,
            "props": {
              "auditLogField": "audit_log",
              "lastN": 5,
              "showTransitionCount": true,
              "showLastTransitionTime": true,
              "showLastActor": true
            }
          }
        ],
        "parameters": [
          {
            "name": "retentionDays",
            "type": "number",
            "required": false,
            "description": "Number of days to retain audit log entries before archival eligibility.\nValue of 0 means indefinite retention. Does not auto-delete — serves as\na policy signal for downstream archival processes.\n",
            "default": 0,
            "validation": {
              "minimum": 0
            }
          },
          {
            "name": "requireTransitionReason",
            "type": "boolean",
            "required": false,
            "description": "When true, every state transition must include a reason string.\nEnforces accountability by preventing silent status changes.\n",
            "default": false
          },
          {
            "name": "trackActorId",
            "type": "boolean",
            "required": false,
            "description": "When true, actor_id is captured on each transition. Enables\nper-user audit trails and accountability reporting.\n",
            "default": true
          }
        ],
        "schema": {
          "audit_log": {
            "type": "AuditEntry[]",
            "required": true,
            "description": "Append-only chronological log of state transition events.\nEach entry captures the full context of a state change.\n",
            "default": [],
            "items": {
              "type": "object",
              "properties": {
                "from_state": {
                  "type": "string",
                  "required": false,
                  "description": "State before the transition. Null for initial state assignment."
                },
                "to_state": {
                  "type": "string",
                  "required": true,
                  "description": "State after the transition."
                },
                "transitioned_at": {
                  "type": "datetime",
                  "required": true,
                  "description": "UTC timestamp when the transition occurred."
                },
                "actor_id": {
                  "type": "string",
                  "required": false,
                  "requiredFromParameter": "trackActorId",
                  "description": "Identifier of the user or system that triggered the transition.\nRequired when trackActorId parameter is true.\n"
                },
                "reason": {
                  "type": "string",
                  "required": false,
                  "requiredFromParameter": "requireTransitionReason",
                  "description": "Human-readable justification for the transition.\nRequired when requireTransitionReason parameter is true.\n"
                },
                "metadata": {
                  "type": "Record<string, unknown>",
                  "required": false,
                  "description": "Arbitrary key-value pairs for domain-specific context\n(e.g., approval_id, ticket_number, automation_rule).\n",
                  "default": {}
                }
              }
            }
          }
        },
        "semantics": {
          "audit_log": {
            "semantic_type": "timeline.audit",
            "token_mapping": "tokenMap(audit.timeline.*)",
            "ui_hints": {
              "component": "AuditTimeline",
              "maxVisible": 7,
              "collapseWhenEmpty": true,
              "entryComponent": "AuditEntryCard"
            }
          },
          "audit_log.from_state": {
            "semantic_type": "audit.transition.from",
            "token_mapping": "tokenMap(audit.state.from)",
            "ui_hints": {
              "component": "StatusBadge",
              "emphasis": "subtle"
            }
          },
          "audit_log.to_state": {
            "semantic_type": "audit.transition.to",
            "token_mapping": "tokenMap(audit.state.to)",
            "ui_hints": {
              "component": "StatusBadge",
              "emphasis": "subtle"
            }
          },
          "audit_log.transitioned_at": {
            "semantic_type": "audit.transition.timestamp",
            "token_mapping": "tokenMap(audit.timestamp.*)",
            "ui_hints": {
              "component": "RelativeTimestamp"
            }
          },
          "audit_log.actor_id": {
            "semantic_type": "audit.transition.actor",
            "token_mapping": "tokenMap(audit.actor.*)",
            "ui_hints": {
              "component": "ActorBadge"
            }
          },
          "audit_log.reason": {
            "semantic_type": "audit.transition.reason",
            "token_mapping": "tokenMap(audit.reason.*)",
            "ui_hints": {
              "component": "TextBody"
            }
          }
        },
        "tokens": {
          "cmp.audit.timeline.connector.color": "var(--sys-border-default)",
          "cmp.audit.timeline.connector.width": "var(--space-px)",
          "cmp.audit.timeline.dot.color": "var(--sys-surface-accent)",
          "cmp.audit.timeline.dot.size": "var(--space-2)",
          "cmp.audit.entry.bg": "var(--sys-surface-raised)",
          "cmp.audit.entry.border": "var(--sys-border-default)",
          "cmp.audit.entry.radius": "var(--radius-md)",
          "cmp.audit.entry.padding": "var(--space-3)",
          "cmp.audit.entry.state.text": "var(--sys-text-strong)",
          "cmp.audit.entry.reason.text": "var(--sys-text-default)",
          "cmp.audit.entry.timestamp.text": "var(--sys-text-subtle)",
          "cmp.audit.entry.actor.text": "var(--sys-text-subtle)",
          "cmp.audit.summary.count.text": "var(--sys-text-strong)",
          "cmp.audit.summary.label.text": "var(--sys-text-subtle)"
        },
        "dependencies": [
          "Stateful"
        ],
        "metadata": {
          "created": "2026-02-28",
          "owners": [
            "compliance@oods.systems",
            "engineering@oods.systems"
          ],
          "maturity": "experimental",
          "accessibility": {
            "keyboard": "AuditTimeline entries are not interactive. Summary card expand/collapse\nis keyboard navigable via Enter/Space.\n",
            "screenreader": "AuditTimeline uses role=\"log\" with aria-label=\"Audit trail\".\nEach entry announces: transition direction (from → to), timestamp,\nactor, and reason as a single description.\nAuditSummaryCard announces total transition count and last activity.\n"
          },
          "regionsUsed": [
            "timeline",
            "detail"
          ],
          "examples": [
            "Subscription",
            "Invoice"
          ],
          "references": [
            "objects/provenance.v1.json#/references/ref-abca58b6f92b — existing timeline renderer",
            "objects/provenance.v1.json#/references/ref-c373015a9045 — StatusTransitionEvent interface (shared shape)",
            "R21.3 Canonical Audit Architecture — compliance-grade audit trail research (200+ pages)",
            "traits/lifecycle/Stateful.trait.yaml — required dependency (state transitions)"
          ]
        },
        "objects": [],
        "source": "traits/lifecycle/Auditable.trait.yaml"
      },
      "Authable": {
        "name": "Authable",
        "version": "1.0.0",
        "description": "Role-based access control extension pack grounded in the R21.2 membership pattern.\nEncodes roles, permissions, memberships, and adjacency edges for tenant-aware RBAC.",
        "category": "core",
        "tags": [
          "authorization",
          "rbac",
          "membership",
          "saas",
          "security"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "RoleBadgeList",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "rolesField": "session_roles",
              "fallbackRoleParameter": "defaultRoleId"
            }
          },
          {
            "component": "MembershipPanel",
            "context": "detail",
            "position": "main",
            "priority": 75,
            "props": {
              "membershipsField": "membership_records",
              "hierarchyField": "role_hierarchy_edges",
              "roleField": "role_catalog",
              "permissionField": "permission_catalog"
            }
          },
          {
            "component": "RoleAssignmentForm",
            "context": "form",
            "position": "main",
            "priority": null,
            "props": {
              "availableRolesField": "role_catalog",
              "membershipField": "membership_records",
              "defaultRoleParameter": "defaultRoleId"
            }
          }
        ],
        "parameters": [
          {
            "name": "defaultRoleId",
            "type": "string",
            "required": false,
            "description": "Role identifier applied when tenants are provisioned without an explicit role (R21.2 §2.3).",
            "validation": {
              "pattern": "^[0-9a-fA-F-]{32,36}$"
            }
          },
          {
            "name": "hierarchyDepthLimit",
            "type": "number",
            "required": false,
            "description": "Maximum recursion depth when traversing role hierarchies for derived permissions.",
            "default": 5,
            "validation": {
              "minimum": 1,
              "maximum": 10
            }
          }
        ],
        "schema": {
          "role_catalog": {
            "type": "AuthzRoleDocument[]",
            "required": true,
            "description": "Canonical RBAC roles (R21.2 Part 4.2 TABLE 1).",
            "examples": [
              [
                {
                  "id": "11111111-1111-4111-8111-111111111111",
                  "name": "Owner",
                  "description": "Full tenant access + invoice approval (R21.2 Table 1)."
                },
                {
                  "id": "22222222-2222-4222-8222-222222222222",
                  "name": "Approver",
                  "description": "Workflow approver for compliance-sensitive documents."
                },
                {
                  "id": "33333333-3333-4333-8333-333333333333",
                  "name": "Editor",
                  "description": "Contributor allowed to create + update documents in scope."
                }
              ]
            ],
            "default": []
          },
          "permission_catalog": {
            "type": "AuthzPermissionDocument[]",
            "required": true,
            "description": "Atomic permissions following resource:action notation (TABLE 2).",
            "default": []
          },
          "role_permissions": {
            "type": "Record<string, string[]>",
            "required": true,
            "description": "Junction map for role→permission edges (TABLE 3).",
            "default": {}
          },
          "membership_records": {
            "type": "AuthzMembershipDocument[]",
            "required": true,
            "description": "SaaS membership triple (user_id, organization_id, role_id) with UNIQUE constraint (TABLE 4).",
            "default": []
          },
          "role_hierarchy_edges": {
            "type": "AuthzRoleHierarchyEdge[]",
            "required": false,
            "description": "Parent→child adjacency list for hierarchical RBAC (Part 3.1).",
            "default": []
          },
          "session_roles": {
            "type": "string[]",
            "required": false,
            "description": "Materialized roles granted within the current session/token exchange.",
            "default": []
          }
        },
        "semantics": {
          "membership_records": {
            "semantic_type": "authorization.memberships",
            "token_mapping": "tokenMap(authorization.memberships)",
            "ui_hints": {
              "component": "MembershipMatrix",
              "uniqueConstraint": "user_id+organization_id+role_id"
            }
          },
          "role_catalog": {
            "semantic_type": "authorization.roles",
            "token_mapping": "tokenMap(authorization.roles)",
            "ui_hints": {
              "component": "RoleCatalogPanel"
            }
          },
          "permission_catalog": {
            "semantic_type": "authorization.permissions",
            "token_mapping": "tokenMap(authorization.permissions)",
            "ui_hints": {
              "component": "PermissionList"
            }
          }
        },
        "tokens": {
          "auth.roles.badge.bg": "var(--sys-surface-neutral)",
          "auth.roles.badge.text": "var(--sys-text-strong)",
          "auth.membership.card.border": "var(--sys-border-strong)",
          "auth.membership.card.bg": "var(--sys-surface-raised)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-19",
          "owners": [
            "security@oods.systems",
            "platform@oods.systems"
          ],
          "maturity": "experimental",
          "accessibility": {
            "keyboard": "RoleAssignmentForm keeps add/remove buttons in reading order.",
            "screenreader": "MembershipPanel announces organization, role, and permission counts per entry."
          },
          "regionsUsed": [
            "list",
            "detail",
            "form"
          ],
          "examples": [
            "User",
            "Organization"
          ],
          "references": [
            "R21.2 Canonical Data Models for Authorization Systems"
          ]
        },
        "objects": [
          "Organization",
          "User"
        ],
        "source": "traits/core/Authable.trait.yaml"
      },
      "Billable": {
        "name": "Billable",
        "version": "2.1.0",
        "description": "Recurring billing mechanics trait that normalizes cycle tracking, payment timing,\nand period management for subscription-based entities. Billable owns the billing\nCYCLE — when payments occur, how periods progress, and what the payment state is.\n\nDISTINCT from Priceable — Priceable handles PRICING (amount, currency, models).\nBillable handles RECURRENCE (cycles, periods, payment timing, proration).\nA Subscription composes both: Priceable for \"how much\" and Billable for \"when/how\".\n\nCore concepts:\n- Billing Cycle: current_period_start → current_period_end with progress tracking\n- Payment Timing: prepaid (charge at period start) vs postpaid (charge at period end)\n- Proration: fractional billing when mid-cycle changes occur, with preview/commit\n  timing (proration_date), a charge-timing policy (prorationBehavior), and\n  billing-anchor-reset disclosure\n- Payment Status: tracks the outcome of the most recent collection attempt\n- Cycle Anchoring: fixed day-of-month for consistent renewal dates\n\nPRORATION SCOPE (trait-split gap): proration semantics live ONLY on this CORE\nfinancial/Billable trait. The saas-billing domain trait SaaSBillingBillable\n(domains/saas-billing/traits/billable.trait.yaml) does NOT expose proration, so a\nSubscription composing only SaaSBillingBillable silently CANNOT prorate. To enable\nproration for a SaaS subscription, compose financial/Billable (as the core\nSubscription object does, alias SubscriptionBilling).",
        "category": "financial",
        "tags": [
          "billing",
          "recurring",
          "financial",
          "cycle",
          "payment",
          "subscription"
        ],
        "contexts": [
          "card",
          "detail",
          "form",
          "list",
          "timeline"
        ],
        "viewExtensions": [
          {
            "component": "BillingSummaryBadge",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "amountField": "amount",
              "currencyField": "currency",
              "intervalField": "billing_interval",
              "minorUnitsParameter": "minorUnits"
            }
          },
          {
            "component": "CycleProgressCard",
            "context": "detail",
            "position": "main",
            "priority": 70,
            "props": {
              "progressField": "current_period_progress",
              "periodStartField": "current_period_start",
              "periodEndField": "current_period_end",
              "intervalField": "billing_interval"
            }
          },
          {
            "component": "PaymentTimeline",
            "context": "detail",
            "position": "main",
            "priority": 60,
            "props": {
              "lastPaymentField": "last_payment_at",
              "nextPaymentField": "next_payment_due_at",
              "paymentStatusField": "payment_status",
              "paymentMethodField": "payment_method_type",
              "amountField": "amount",
              "currencyField": "currency"
            }
          },
          {
            "component": "BillingIntervalSelector",
            "context": "form",
            "position": "main",
            "priority": 80,
            "props": {
              "intervalField": "billing_interval",
              "intervalsParameter": "billingIntervals"
            }
          },
          {
            "component": "BillingAmountInput",
            "context": "form",
            "position": "main",
            "priority": 75,
            "props": {
              "amountField": "amount",
              "currencyField": "currency",
              "minorUnitsParameter": "minorUnits"
            }
          },
          {
            "component": "PaymentEventTimeline",
            "context": "timeline",
            "position": null,
            "priority": null,
            "props": {
              "lastPaymentField": "last_payment_at",
              "nextPaymentField": "next_payment_due_at",
              "paymentStatusField": "payment_status",
              "amountField": "amount",
              "currencyField": "currency"
            }
          },
          {
            "component": "BillingCardMeta",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "amountField": "amount",
              "currencyField": "currency",
              "intervalField": "billing_interval",
              "minorUnitsParameter": "minorUnits"
            }
          }
        ],
        "parameters": [
          {
            "name": "defaultCurrency",
            "type": "string",
            "required": false,
            "description": "ISO 4217 currency code used when a value is not explicitly provided.",
            "default": "usd",
            "validation": {
              "pattern": "^[a-zA-Z]{3}$"
            }
          },
          {
            "name": "billingIntervals",
            "type": "string[]",
            "required": false,
            "description": "Allowed billing interval values that downstream objects may select.",
            "default": [
              "monthly",
              "quarterly",
              "annual"
            ]
          },
          {
            "name": "minorUnits",
            "type": "number",
            "required": false,
            "description": "Number of fractional units that constitute a single major currency unit (e.g., 100 for cents).",
            "default": 100,
            "validation": {
              "minimum": 1
            }
          },
          {
            "name": "paymentTiming",
            "type": "string",
            "required": false,
            "description": "Whether the billing entity charges at the start of the period (prepaid)\nor at the end (postpaid). Affects cycle progress interpretation and\ndunning trigger points.\n",
            "default": "prepaid",
            "validation": {
              "enum": [
                "prepaid",
                "postpaid"
              ]
            }
          },
          {
            "name": "supportProration",
            "type": "boolean",
            "required": false,
            "description": "Whether mid-cycle plan changes generate prorated charges or credits.\nWhen true, proration_amount is computed on plan upgrades/downgrades.\n",
            "default": false
          },
          {
            "name": "prorationBehavior",
            "type": "string",
            "required": false,
            "description": "Default policy for how mid-cycle plan changes are billed, mirroring Stripe's\nproration_behavior on subscription updates. Drives charge TIMING, not the\nproration math, and is only meaningful when supportProration is true:\n- create_prorations: generate prorated line items, billed on the next invoice (default)\n- always_invoice: generate prorations AND invoice them immediately\n- none: apply the change with no proration line items / no immediate adjustment\nSource: docs.stripe.com/billing/subscriptions/prorations.\n",
            "default": "create_prorations",
            "validation": {
              "enum": [
                "create_prorations",
                "always_invoice",
                "none"
              ]
            }
          },
          {
            "name": "cycleAnchorDay",
            "type": "number",
            "required": false,
            "description": "Day of the month used to anchor renewal dates. When set, all billing\nperiods align to this day regardless of subscription start date.\nValue of 0 means no anchoring (period starts from subscription creation).\n\nBILLING-ANCHOR-RESET DISCLOSURE: changing the billing interval — or otherwise\nresetting the billing cycle anchor (e.g. Stripe billing_cycle_anchor=now) — RESETS\nthe anchor and starts a new billing period immediately. This interacts with\nproration: the reset can itself trigger proration for the current period and shifts\nthe renewal date. Surface this consequence to the user BEFORE applying an interval\nchange. Source: docs.stripe.com/billing/subscriptions/prorations.\n",
            "default": 0,
            "validation": {
              "minimum": 0,
              "maximum": 31
            }
          }
        ],
        "schema": {
          "amount": {
            "type": "integer",
            "required": true,
            "description": "Recurring price expressed in minor currency units (e.g., cents).",
            "validation": {
              "minimum": 0
            }
          },
          "currency": {
            "type": "string",
            "required": true,
            "description": "ISO 4217 currency code for the billing amount.",
            "validation": {
              "pattern": "^[a-zA-Z]{3}$"
            }
          },
          "billing_interval": {
            "type": "string",
            "required": true,
            "description": "Recurrence cadence label selected from the billingIntervals parameter.",
            "validation": {
              "enumFromParameter": "billingIntervals"
            }
          },
          "payment_status": {
            "type": "string",
            "required": false,
            "description": "Outcome of the most recent collection attempt. Distinct from subscription\nlifecycle status — a subscription can be \"active\" with payment_status \"retrying\".\n",
            "validation": {
              "enum": [
                "pending",
                "succeeded",
                "failed",
                "retrying",
                "refunded"
              ]
            },
            "default": "pending"
          },
          "payment_method_type": {
            "type": "string",
            "required": false,
            "description": "Payment instrument category used for collection.",
            "validation": {
              "enum": [
                "card",
                "ach",
                "wire",
                "invoice",
                "other"
              ]
            }
          },
          "proration_amount": {
            "type": "integer",
            "required": false,
            "description": "Prorated credit or charge in minor currency units generated by a mid-cycle\nplan change. Positive values are charges; negative values are credits.\nOnly populated when the supportProration parameter is true.\n",
            "default": 0
          },
          "proration_date": {
            "type": "integer",
            "required": false,
            "description": "Unix timestamp (epoch SECONDS) at which proration is calculated. Pinned when an\nupcoming-invoice PREVIEW is requested and MUST be passed identically on commit so the\ncommitted charge equals the previewed amount. The preview is read-only and does NOT\nmutate the subscription. Stored as an integer (not a datetime) so the value round-trips\nbyte-identically between preview and commit — an ISO string normalization could shift it\nand desync the previewed vs charged amount. Only populated when supportProration is true.\nSource: docs.stripe.com/billing/subscriptions/prorations.\n",
            "validation": {
              "minimum": 0
            }
          },
          "last_payment_at": {
            "type": "datetime",
            "required": false,
            "description": "Timestamp of the most recent successful payment."
          },
          "next_payment_due_at": {
            "type": "datetime",
            "required": false,
            "description": "Timestamp when the next payment attempt is scheduled."
          },
          "current_period_start": {
            "type": "datetime",
            "required": false,
            "description": "Beginning timestamp of the active billing cycle."
          },
          "current_period_end": {
            "type": "datetime",
            "required": false,
            "description": "Ending timestamp of the active billing cycle."
          },
          "current_period_progress": {
            "type": "number",
            "required": false,
            "description": "Decimal (0.0–1.0) indicating progress through the active billing cycle.",
            "validation": {
              "minimum": 0,
              "maximum": 1
            }
          }
        },
        "semantics": {
          "amount": {
            "semantic_type": "billing.cycle.amount_minor",
            "token_mapping": "tokenMap(billing.amount.*)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnitsParameter": "minorUnits"
            }
          },
          "currency": {
            "semantic_type": "billing.cycle.currency",
            "token_mapping": "tokenMap(billing.currency.*)",
            "ui_hints": {
              "component": "CurrencyCode"
            }
          },
          "billing_interval": {
            "semantic_type": "billing.cycle.interval",
            "token_mapping": "tokenMap(billing.interval.*)",
            "ui_hints": {
              "component": "BillingIntervalBadge",
              "parameterSource": "billingIntervals"
            }
          },
          "payment_status": {
            "semantic_type": "billing.cycle.payment_status",
            "token_mapping": "tokenMap(billing.payment.status.*)",
            "ui_hints": {
              "component": "PaymentStatusBadge"
            }
          },
          "payment_method_type": {
            "semantic_type": "billing.cycle.payment_method",
            "token_mapping": "tokenMap(billing.payment.method.*)",
            "ui_hints": {
              "component": "PaymentMethodIcon"
            }
          },
          "proration_amount": {
            "semantic_type": "billing.cycle.proration",
            "token_mapping": "tokenMap(billing.proration.*)",
            "ui_hints": {
              "minorUnitsParameter": "minorUnits",
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "signIndicator": true
            }
          },
          "proration_date": {
            "semantic_type": "billing.cycle.proration_timestamp",
            "token_mapping": "tokenMap(billing.timestamp.proration)",
            "ui_hints": {
              "component": "Timestamp",
              "unixSeconds": true
            }
          },
          "last_payment_at": {
            "semantic_type": "billing.cycle.last_payment_at",
            "token_mapping": "tokenMap(billing.timestamp.last_payment)",
            "ui_hints": {
              "component": "RelativeTimestamp"
            }
          },
          "next_payment_due_at": {
            "semantic_type": "billing.cycle.next_payment_due_at",
            "token_mapping": "tokenMap(billing.timestamp.next_payment)",
            "ui_hints": {
              "component": "RelativeTimestamp",
              "urgencyThresholdDays": 3
            }
          },
          "current_period_start": {
            "semantic_type": "billing.cycle.period_start",
            "token_mapping": "tokenMap(billing.timestamp.period_start)",
            "ui_hints": {
              "component": "Timestamp"
            }
          },
          "current_period_end": {
            "semantic_type": "billing.cycle.period_end",
            "token_mapping": "tokenMap(billing.timestamp.period_end)",
            "ui_hints": {
              "component": "Timestamp"
            }
          },
          "current_period_progress": {
            "semantic_type": "billing.cycle.period_progress",
            "token_mapping": "tokenMap(billing.cycle.progress)",
            "ui_hints": {
              "component": "CycleProgressBar"
            }
          }
        },
        "tokens": {
          "cmp.billing.amount.text": "var(--sys-text-strong)",
          "cmp.billing.amount.currency": "var(--sys-text-subtle)",
          "cmp.billing.amount.interval": "var(--sys-text-subtle)",
          "cmp.billing.cycle.progress.track": "var(--sys-surface-neutral)",
          "cmp.billing.cycle.progress.fill": "var(--sys-surface-accent)",
          "cmp.billing.cycle.progress.text": "var(--sys-text-default)",
          "cmp.billing.cycle.progress.height": "var(--space-1)",
          "cmp.billing.cycle.progress.radius": "var(--radius-full)",
          "cmp.billing.payment.succeeded.bg": "var(--sys-surface-success)",
          "cmp.billing.payment.succeeded.text": "var(--sys-text-success)",
          "cmp.billing.payment.failed.bg": "var(--sys-surface-critical)",
          "cmp.billing.payment.failed.text": "var(--sys-text-critical)",
          "cmp.billing.payment.retrying.bg": "var(--sys-surface-warning)",
          "cmp.billing.payment.retrying.text": "var(--sys-text-warning)",
          "cmp.billing.payment.pending.bg": "var(--sys-surface-info)",
          "cmp.billing.payment.pending.text": "var(--sys-text-info)",
          "cmp.billing.timeline.connector": "var(--sys-border-default)",
          "cmp.billing.timeline.dot": "var(--sys-surface-accent)",
          "cmp.billing.timeline.text": "var(--sys-text-default)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-10-16",
          "updated": "2026-06-24",
          "owners": [
            "billing@oods.systems",
            "finance@oods.systems"
          ],
          "maturity": "experimental",
          "accessibility": {
            "keyboard": "BillingIntervalSelector is keyboard navigable via arrow keys.\nBillingAmountInput supports standard numeric input patterns.\n",
            "screenreader": "BillingSummaryBadge announces amount, currency, and interval as a single phrase.\nCycleProgressCard announces progress percentage and remaining days.\nPaymentStatusBadge announces payment outcome with tone-appropriate urgency.\n"
          },
          "regionsUsed": [
            "list",
            "detail",
            "form",
            "timeline",
            "card"
          ],
          "examples": [
            "Subscription",
            "Plan"
          ],
          "references": [
            "objects/provenance.v1.json#/references/ref-0d9aaa77f987 — BillableViewData, BillingSummary, PastDueAction",
            "objects/provenance.v1.json#/references/ref-374e980524b1 — CanonicalSubscription, BillingInterval, BillingAccount",
            "domains/saas-billing/traits/billable.trait.yaml — SaaS domain extension",
            "objects/core/Subscription.object.yaml — Subscription object composition",
            "objects/provenance.v1.json#/references/ref-be33a98177f7 — billing domain status tokens"
          ]
        },
        "objects": [
          "Subscription"
        ],
        "source": "traits/financial/Billable.trait.yaml"
      },
      "Cancellable": {
        "name": "Cancellable",
        "version": "1.0.0",
        "description": "Adds lifecycle-aware cancellation workflows with policy guardrails and semantic token mappings.",
        "category": "lifecycle",
        "tags": [
          "lifecycle",
          "cancellation",
          "retention",
          "workflow"
        ],
        "contexts": [
          "card",
          "detail",
          "form"
        ],
        "viewExtensions": [
          {
            "component": "CancellationSummary",
            "context": "detail",
            "position": "top",
            "priority": null,
            "props": {
              "hideWhenDefault": true,
              "cancelAtPeriodEndField": "cancel_at_period_end",
              "reasonField": "cancellation_reason",
              "codeField": "cancellation_reason_code",
              "requestedAtField": "cancellation_requested_at"
            }
          },
          {
            "component": "CancellationForm",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "reasonField": "cancellation_reason",
              "codeField": "cancellation_reason_code",
              "requireReasonParameter": "requireReason",
              "allowedReasonsParameter": "allowedReasons",
              "windowParameter": "cancellationWindowHours"
            }
          },
          {
            "component": "CancellationBadge",
            "context": "card",
            "position": "before",
            "priority": null,
            "props": {
              "field": "cancel_at_period_end",
              "hideWhenFalse": true
            }
          }
        ],
        "parameters": [
          {
            "name": "allowCancellationAfterStart",
            "type": "boolean",
            "required": false,
            "description": "Whether cancellation may occur after the entity transitions to an active state.",
            "default": true
          },
          {
            "name": "cancellationWindowHours",
            "type": "number",
            "required": false,
            "description": "Number of hours after activation where cancellation is permitted.",
            "validation": {
              "minimum": 0,
              "maximum": 720
            }
          },
          {
            "name": "requireReason",
            "type": "boolean",
            "required": false,
            "description": "Whether a structured cancellation reason must be supplied by the actor.",
            "default": false
          },
          {
            "name": "allowedReasons",
            "type": "string[]",
            "required": false,
            "description": "Allow list of valid cancellation reason codes when requireReason is true.",
            "validation": {
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "pattern": "^[a-z0-9_\\-]+$",
                "minLength": 1,
                "maxLength": 64
              }
            }
          }
        ],
        "schema": {
          "cancel_at_period_end": {
            "type": "boolean",
            "required": true,
            "description": "Whether cancellation occurs at the natural period end instead of immediately. When true the entity is in a REVERSIBLE pending-cancellation state: the schedule can be undone (set back to false) any time before period end, returning the entity to active. This is distinct from a terminal cancellation (a `terminated`/canceled subscription), which is irreversible and non-reactivatable. Mirrors Stripe's cancel_at_period_end flag (docs.stripe.com/billing/subscriptions/cancel).",
            "default": false
          },
          "cancellation_reason": {
            "type": "string",
            "required": false,
            "description": "Free-form detail describing why cancellation occurred.",
            "validation": {
              "maxLength": 160
            }
          },
          "cancellation_reason_code": {
            "type": "string",
            "required": false,
            "description": "Structured reason code chosen from the allowedReasons parameter.",
            "validation": {
              "enumFromParameter": "allowedReasons"
            }
          },
          "cancellation_requested_at": {
            "type": "datetime",
            "required": false,
            "description": "Timestamp capturing when the cancellation workflow was initiated."
          }
        },
        "semantics": {
          "cancel_at_period_end": {
            "semantic_type": "status.cancel.deferred",
            "token_mapping": "tokenMap(status.cancel.*)",
            "ui_hints": {
              "component": "CancellationToggle",
              "emphasizeWhenTrue": true
            }
          },
          "cancellation_reason": {
            "semantic_type": "status.cancel.reason",
            "token_mapping": "tokenMap(status.cancel.reason)",
            "ui_hints": {
              "component": "CancellationReason",
              "multiline": true,
              "maxLength": 160
            }
          },
          "cancellation_reason_code": {
            "semantic_type": "status.cancel.reason_code",
            "token_mapping": "tokenMap(status.cancel.code.*)",
            "ui_hints": {
              "component": "ReasonPicker",
              "parameterSource": "allowedReasons"
            }
          },
          "cancellation_requested_at": {
            "semantic_type": "status.cancel.timestamp",
            "token_mapping": "tokenMap(status.cancel.timestamp)",
            "ui_hints": {
              "component": "TimelineTimestamp"
            }
          }
        },
        "tokens": {
          "status.cancel.primary.bg": "var(--status-cancel-bg)",
          "status.cancel.primary.text": "var(--status-cancel-text)",
          "status.cancel.reason.text": "var(--text-default)",
          "status.cancel.timestamp.text": "var(--text-subtle)"
        },
        "dependencies": [
          "Stateful"
        ],
        "metadata": {
          "created": "2025-10-12",
          "owners": [
            "lifecycle@oods.systems",
            "support@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "Supports toggling of cancellation switches.",
            "screenreader": "Announces cancellation state and reason."
          },
          "regionsUsed": [
            "detail",
            "form",
            "card"
          ],
          "examples": [
            "Subscription",
            "Reservation"
          ],
          "references": [
            "Trait Engine Spec v0.1 §2"
          ]
        },
        "objects": [
          "Subscription",
          "Transaction"
        ],
        "source": "traits/lifecycle/Cancellable.trait.yaml"
      },
      "Classifiable": {
        "name": "Classifiable",
        "version": "1.0.0",
        "description": "Canonical taxonomy + folksonomy trait supporting taxonomy, tag, and hybrid modes with governance metadata.",
        "category": "core",
        "tags": [
          "taxonomy",
          "tags",
          "ltree",
          "classification",
          "governance"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "ClassificationBadge",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "mode": "{classification_mode}",
              "primaryCategoryField": "primary_category_id",
              "tagPreviewField": "tag_preview"
            }
          },
          {
            "component": "ClassificationPanel",
            "context": "detail",
            "position": "sidebar",
            "priority": 40,
            "props": {
              "categoriesField": "categories",
              "tagsField": "tags",
              "metadataField": "classification_metadata",
              "modeParameter": "classification_mode"
            }
          },
          {
            "component": "ClassificationEditor",
            "context": "form",
            "position": "main",
            "priority": null,
            "props": {
              "modeParameter": "classification_mode",
              "tagPolicyParameter": "tag_policy",
              "maxTagsParameter": "max_tags"
            }
          }
        ],
        "parameters": [
          {
            "name": "classification_mode",
            "type": "enum",
            "required": true,
            "enum": [
              "taxonomy",
              "tag",
              "hybrid"
            ],
            "default": "hybrid",
            "description": "taxonomy = hierarchical only, tag = folksonomy only, hybrid = WordPress three-table pattern.\n"
          },
          {
            "name": "hierarchy_storage_model",
            "type": "enum",
            "required": false,
            "enum": [
              "adjacency_list",
              "materialized_path",
              "closure_table"
            ],
            "default": "materialized_path",
            "description": "Storage pattern for taxonomy hierarchies. materialized_path assumes ltree for <3ms subtree queries.\n"
          },
          {
            "name": "tag_policy",
            "type": "enum",
            "required": false,
            "enum": [
              "locked",
              "moderated",
              "open"
            ],
            "default": "moderated",
            "description": "Controls whether tags are curated only (locked), require moderation, or are open to user generation.\n"
          },
          {
            "name": "max_tags",
            "type": "number",
            "required": false,
            "default": 10,
            "description": "Maximum number of canonical tags per object.",
            "validation": {
              "minimum": 1,
              "maximum": 50
            }
          },
          {
            "name": "require_primary_category",
            "type": "boolean",
            "required": false,
            "default": false,
            "description": "Require at least one primary taxonomy category."
          }
        ],
        "schema": {
          "classification_metadata": {
            "type": "ClassificationMetadata",
            "required": true,
            "description": "Operational metadata describing mode, storage model, governance rules, and audit timestamps.\n"
          },
          "categories": {
            "type": "CategoryNode[]",
            "required": false,
            "default": [],
            "description": "Ordered taxonomy nodes scoped to the object."
          },
          "primary_category_id": {
            "type": "string",
            "required": false,
            "description": "Identifier of the canonical taxonomy node."
          },
          "primary_category_path": {
            "type": "string",
            "required": false,
            "description": "Human-readable breadcrumb path (Electronics > Mobile > Android)."
          },
          "tags": {
            "type": "Tag[]",
            "required": false,
            "default": [],
            "description": "Canonical tag collection after synonym collapse."
          },
          "tag_count": {
            "type": "number",
            "required": false,
            "default": 0,
            "description": "Number of canonical tags assigned to the object."
          },
          "tag_preview": {
            "type": "string",
            "required": false,
            "description": "Denormalized comma-delimited preview for list renders."
          }
        },
        "semantics": {
          "classification_metadata": {
            "semantic_type": "classification.metadata",
            "token_mapping": "tokenMap(classification.metadata)",
            "ui_hints": {
              "component": "ClassificationDiagnostics"
            }
          },
          "categories": {
            "semantic_type": "classification.categories",
            "token_mapping": "tokenMap(classification.categories.*)",
            "ui_hints": {
              "component": "CategoryTree"
            }
          },
          "tags": {
            "semantic_type": "classification.tags",
            "token_mapping": "tokenMap(classification.tags.*)",
            "ui_hints": {
              "component": "TagTokenCloud",
              "policyParameter": "tag_policy"
            }
          },
          "primary_category_id": {
            "semantic_type": "classification.primary",
            "token_mapping": "tokenMap(classification.primary)",
            "ui_hints": {
              "component": "CategoryBreadcrumb"
            }
          }
        },
        "tokens": {
          "classification": {
            "category": {
              "badge": {
                "bg": "var(--sys-surface-raised)",
                "border": "var(--sys-border-strong)"
              }
            },
            "tag": {
              "chip": {
                "bg": "var(--sys-surface-muted)",
                "text": "var(--sys-text-strong)"
              }
            }
          }
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-18T00:00:00.000Z",
          "updated": "2025-11-18T00:00:00.000Z",
          "owners": [
            "core@oods.systems",
            "taxonomy@oods.systems"
          ],
          "maturity": "draft",
          "references": [
            "R21.4_Deep-Dive-Implementation-Research-for-the-Classifiable-Core-Trait.md",
            "Core_Traits_Specification_Draft.md"
          ],
          "regionsUsed": [
            "list",
            "detail",
            "form"
          ]
        },
        "objects": [
          "Article",
          "Media",
          "Product"
        ],
        "source": "traits/core/Classifiable.trait.yaml"
      },
      "Colorized": {
        "name": "Colorized",
        "version": "2.0.0",
        "description": "Maps lifecycle states to semantic color tokens for consistent status theming across the\ndesign system. Colorized is the visual bridge between the Stateful trait's data model and\nthe OODS token system's three-tier architecture (ref → theme → system → component).\n\nEvery object that composes Stateful should also compose Colorized so that status values\nresolve to a deterministic set of surface, border, text, and icon tokens. The trait\nencodes WCAG contrast enforcement, color-blind safety via redundant icon+text cues,\nand theme-aware OKLCH token resolution — ensuring status communication never relies\non color alone.",
        "category": "visual",
        "tags": [
          "color",
          "semantic",
          "status",
          "theming",
          "accessibility",
          "oklch",
          "tokens"
        ],
        "contexts": [
          "card",
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "ColorSwatch",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "field": "color_state",
              "size": "sm"
            }
          },
          {
            "component": "StatusColorLegend",
            "context": "detail",
            "position": "top",
            "priority": null,
            "props": {
              "parameter": "colorStates",
              "badgeField": "color_state",
              "showTokenReferences": true
            }
          },
          {
            "component": "ColorStatePicker",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "parameter": "colorStates",
              "field": "color_state"
            }
          },
          {
            "component": "ColorizedBadge",
            "context": "card",
            "position": "before",
            "priority": null,
            "props": {
              "field": "color_state",
              "tone": "status",
              "showIcon": true
            }
          }
        ],
        "parameters": [
          {
            "name": "colorStates",
            "type": "string[]",
            "required": true,
            "description": "Semantic tone keys that define the palette of status colors available to this object.\nEach key maps to a --cmp-status-{tone}-{surface|border|text|icon} token set.\nMust be a subset of the canonical tones defined in the status token layer.\n",
            "default": [
              "neutral",
              "info",
              "success",
              "warning",
              "critical"
            ],
            "validation": {
              "items": {
                "enum": [
                  "neutral",
                  "info",
                  "accent",
                  "success",
                  "warning",
                  "critical"
                ]
              }
            }
          },
          {
            "name": "contrastLevel",
            "type": "string",
            "required": false,
            "description": "WCAG contrast compliance target for all color pairings produced by this trait.\nAA requires 4.5:1 for normal text and 3:1 for large text / UI components.\nAAA requires 7:1 for normal text and 4.5:1 for large text.\nEnforced at build time by pnpm tokens:guardrails (OKLCH delta-L >= 10, delta-C <= 0.04).\n",
            "default": "AA",
            "validation": {
              "enum": [
                "AA",
                "AAA"
              ]
            }
          },
          {
            "name": "colorMode",
            "type": "string",
            "required": false,
            "description": "Controls how color_state values resolve to tokens.\n- semantic: Tones map to the system status token layer (--sys-status-{tone}-*).\n  This is the default and recommended mode for most objects.\n- custom: Tones map to object-specific component tokens (--cmp-{object}-status-{tone}-*).\n  Use when an object needs domain-specific color semantics (e.g., billing severity).\n",
            "default": "semantic",
            "validation": {
              "enum": [
                "semantic",
                "custom"
              ]
            }
          },
          {
            "name": "fallbackTone",
            "type": "string",
            "required": false,
            "description": "Tone applied when a status value cannot be resolved to a known color state.\nPrevents rendering blank or unstyled badges when status data is missing or unknown.\n",
            "default": "neutral",
            "validation": {
              "enum": [
                "neutral",
                "info",
                "accent",
                "success",
                "warning",
                "critical"
              ]
            }
          }
        ],
        "schema": {
          "color_state": {
            "type": "string",
            "required": true,
            "description": "Active semantic tone key derived from the object's current Stateful status.\nResolved at runtime by the statusRegistry via tone inference from token references.\nMust be one of the values defined in the colorStates parameter.\n",
            "validation": {
              "enumFromParameter": "colorStates"
            }
          },
          "resolved_token_set": {
            "type": "object",
            "required": false,
            "computed": true,
            "description": "Materialized CSS custom property map for the active color_state. Populated at render\ntime by the statusRegistry (src/components/statusables/statusRegistry.ts).\nContains surface, border, text, and optional icon token references.\n",
            "properties": {
              "surface": {
                "type": "string",
                "description": "Background token, e.g. var(--cmp-status-success-surface)"
              },
              "border": {
                "type": "string",
                "description": "Border token, e.g. var(--cmp-status-success-border)"
              },
              "text": {
                "type": "string",
                "description": "Foreground text token, e.g. var(--cmp-status-success-text)"
              },
              "icon": {
                "type": "string",
                "description": "Optional icon color token, e.g. var(--cmp-status-success-icon)"
              }
            }
          },
          "accessibility_label": {
            "type": "string",
            "required": false,
            "computed": true,
            "description": "Human-readable status label announced by screen readers. Generated from the\ncolor_state value via toLabel() (e.g., \"past_due\" → \"Past Due\"). Ensures status\nmeaning is communicated without reliance on color perception.\n"
          }
        },
        "semantics": {
          "color_state": {
            "semantic_type": "status.visual",
            "token_mapping": "tokenMap(status.state.*)",
            "ui_hints": {
              "component": "ColorTokenBadge",
              "parameterSource": "colorStates"
            }
          },
          "resolved_token_set": {
            "semantic_type": "status.visual.tokens",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "internal",
              "description": "Consumed by StatusBadge and ColorizedBadge at render time."
            }
          }
        },
        "tokens": {
          "status.state.badge.radius": "var(--radius-md)",
          "status.state.badge.gap": "var(--space-1)",
          "status.state.badge.icon.size": "var(--size-2)",
          "cmp-status-neutral-surface": "var(--sys-status-neutral-surface)",
          "cmp-status-neutral-border": "var(--sys-status-neutral-border)",
          "cmp-status-neutral-text": "var(--sys-status-neutral-text)",
          "cmp-status-neutral-icon": "var(--sys-status-neutral-icon)",
          "cmp-status-info-surface": "var(--sys-status-info-surface)",
          "cmp-status-info-border": "var(--sys-status-info-border)",
          "cmp-status-info-text": "var(--sys-status-info-text)",
          "cmp-status-info-icon": "var(--sys-status-info-icon)",
          "cmp-status-accent-surface": "var(--sys-status-accent-surface)",
          "cmp-status-accent-border": "var(--sys-status-accent-border)",
          "cmp-status-accent-text": "var(--sys-status-accent-text)",
          "cmp-status-accent-icon": "var(--sys-status-accent-icon)",
          "cmp-status-success-surface": "var(--sys-status-success-surface)",
          "cmp-status-success-border": "var(--sys-status-success-border)",
          "cmp-status-success-text": "var(--sys-status-success-text)",
          "cmp-status-success-icon": "var(--sys-status-success-icon)",
          "cmp-status-warning-surface": "var(--sys-status-warning-surface)",
          "cmp-status-warning-border": "var(--sys-status-warning-border)",
          "cmp-status-warning-text": "var(--sys-status-warning-text)",
          "cmp-status-warning-icon": "var(--sys-status-warning-icon)",
          "cmp-status-critical-surface": "var(--sys-status-critical-surface)",
          "cmp-status-critical-border": "var(--sys-status-critical-border)",
          "cmp-status-critical-text": "var(--sys-status-critical-text)",
          "cmp-status-critical-icon": "var(--sys-status-critical-icon)",
          "cmp-banner-background": "var(--sys-surface-neutral)",
          "cmp-banner-border": "var(--sys-border-neutral)",
          "cmp-banner-text": "var(--sys-text-neutral)"
        },
        "dependencies": [
          "Stateful"
        ],
        "metadata": {
          "created": "2025-10-12",
          "updated": "2026-02-28",
          "owners": [
            "design@oods.systems",
            "engineering@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "n/a — Colorized is a visual presentation trait with no interactive elements.",
            "screenreader": "StatusBadge announces the accessibility_label (human-readable status) and tone.\nColor is never the sole channel for status information.\n",
            "colorBlind": "All status badges MUST include both an icon and text label alongside the color indicator.\nThis icon+text redundancy requirement ensures that deuteranopia, protanopia, and\ntritanopia users can distinguish statuses without relying on hue perception.\nThe fallbackTone parameter provides a safe default when tone inference fails.\n",
            "contrastEnforcement": "WCAG compliance is enforced at two levels:\n  1. Build-time: pnpm tokens:guardrails checks OKLCH delta-L >= 10 and delta-C <= 0.04\n     for all interactive state transitions (hover, focus, active).\n  2. Design-time: All text-on-surface pairings in the status token layer meet the\n     contrast ratio specified by the contrastLevel parameter (4.5:1 for AA, 7:1 for AAA).\nDark theme tokens (themes/dark/status.json) use direct OKLCH values tuned to maintain\nthese ratios against dark surfaces.\n"
          },
          "regionsUsed": [
            "list",
            "detail",
            "form",
            "card"
          ],
          "examples": [
            "Incident",
            "Release",
            "Subscription",
            "Invoice"
          ],
          "stateToToneMapping": {
            "description": "Canonical mapping from domain status strings to semantic tones, as implemented\nin statusRegistry.ts TOKEN_TONE_ALIASES. Objects may define additional aliases\nin their domain-specific status-map JSON files.\n",
            "mappings": [
              {
                "tone": "info",
                "aliases": [
                  "info",
                  "informational",
                  "pending"
                ]
              },
              {
                "tone": "accent",
                "aliases": [
                  "accent",
                  "highlight"
                ]
              },
              {
                "tone": "success",
                "aliases": [
                  "positive",
                  "success",
                  "ok",
                  "active"
                ]
              },
              {
                "tone": "warning",
                "aliases": [
                  "warning",
                  "caution"
                ]
              },
              {
                "tone": "critical",
                "aliases": [
                  "danger",
                  "critical",
                  "error",
                  "negative",
                  "terminated"
                ]
              },
              {
                "tone": "neutral",
                "aliases": [
                  "neutral"
                ]
              }
            ]
          },
          "references": [
            "Trait Engine Spec v0.1 section 2",
            "WCAG 2.1 Success Criterion 1.4.1 — Use of Color",
            "WCAG 2.1 Success Criterion 1.4.3 — Contrast (Minimum)",
            "WCAG 2.1 Success Criterion 1.4.11 — Non-text Contrast",
            "objects/provenance.v1.json#/references/ref-ca663a7c5731 — runtime tone resolution",
            "objects/provenance.v1.json#/references/ref-a6f66bd53aac — system status tokens",
            "objects/provenance.v1.json#/references/ref-559f1f5ebb77 — dark theme OKLCH values",
            "objects/provenance.v1.json#/references/ref-be33a98177f7 — domain status mapping example"
          ]
        },
        "objects": [],
        "source": "traits/visual/Colorized.trait.yaml"
      },
      "Communicable": {
        "name": "Communicable",
        "version": "1.0.0",
        "description": "Canonical communication trait that unifies multi-channel delivery, template governance,\ndelivery policies, and threaded conversations derived from R20.1/R20.6 research. Provides\norchestration-ready schemas for channels, messages, policies, and conversations with\nPreferenceable/Authable/Classifiable integration points.",
        "category": "communication",
        "tags": [
          "notification",
          "messaging",
          "template",
          "delivery",
          "conversation"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "MessageStatusBadge",
            "context": "list",
            "position": "before",
            "priority": 90,
            "props": {
              "statusesField": "message_statuses"
            }
          },
          {
            "component": "CommunicationDetailPanel",
            "context": "detail",
            "position": "main",
            "priority": 80,
            "props": {
              "channelsField": "channel_catalog",
              "templatesField": "template_catalog",
              "policiesField": "delivery_policies",
              "conversationsField": "conversations"
            }
          },
          {
            "component": "TemplatePicker",
            "context": "form",
            "position": "main",
            "priority": null,
            "props": {
              "templatesField": "template_catalog",
              "channelsField": "channel_catalog"
            }
          }
        ],
        "parameters": [
          {
            "name": "channelTypes",
            "type": "string[]",
            "required": false,
            "default": [
              "email",
              "sms",
              "push",
              "in_app",
              "webhook"
            ],
            "description": "Channels enabled for the tenant (R20.1 Part 2.1 multi-channel taxonomy)."
          },
          {
            "name": "supportConversations",
            "type": "boolean",
            "required": false,
            "default": true,
            "description": "Toggle for threaded conversations in addition to standalone messages."
          }
        ],
        "schema": {
          "channel_catalog": {
            "type": "Channel[]",
            "required": true,
            "description": "Provider configuration for each channel (SMTP/Twilio/FCM/Webhook).",
            "examples": [
              [
                {
                  "id": "44444444-dddd-4ddd-8ddd-dddddddddddd",
                  "name": "Primary Email (SMTP)",
                  "type": "email"
                },
                {
                  "id": "55555555-eeee-4eee-8eee-eeeeeeeeeeee",
                  "name": "Twilio SMS",
                  "type": "sms"
                },
                {
                  "id": "66666666-ffff-4fff-8fff-ffffffffffff",
                  "name": "FCM Push",
                  "type": "push"
                },
                {
                  "id": "77777777-0000-4000-8000-000000000000",
                  "name": "Realtime In-App",
                  "type": "in_app"
                }
              ]
            ],
            "default": []
          },
          "template_catalog": {
            "type": "Template[]",
            "required": true,
            "description": "Localized template definitions with declared variables per R20.1 Part 2.3.",
            "examples": [
              [
                {
                  "id": "88888888-1111-4111-8111-111111111111",
                  "name": "Welcome Email",
                  "channelType": "email",
                  "subject": "Welcome to OODS Foundry, {{firstName}}!",
                  "body": "Hi {{firstName}},\n\nThanks for joining {{workspaceName}}. Activate your account using {{activationLink}}.",
                  "variables": [
                    "firstName",
                    "workspaceName",
                    "activationLink"
                  ],
                  "locale": "en-US"
                },
                {
                  "id": "99999999-2222-4222-8222-222222222222",
                  "name": "Password Reset Email",
                  "channelType": "email",
                  "subject": "Reset your OODS Foundry password",
                  "body": "Hello {{firstName}},\n\nWe received a request to reset your password. Use this code: {{resetCode}}.",
                  "variables": [
                    "firstName",
                    "resetCode"
                  ],
                  "locale": "en-US"
                },
                {
                  "id": "aaaaaaa1-3333-4333-8333-333333333333",
                  "name": "In-App Notification",
                  "channelType": "in_app",
                  "subject": "New document shared with you",
                  "body": "{{actorName}} shared \"{{documentName}}\" with you. Review it before {{dueDate}}.",
                  "variables": [
                    "actorName",
                    "documentName",
                    "dueDate"
                  ],
                  "locale": "en-US"
                }
              ]
            ],
            "default": []
          },
          "delivery_policies": {
            "type": "DeliveryPolicy[]",
            "required": true,
            "description": "Retry/throttle/quiet-hour policies (R20.1 Part 3 lifecycle).",
            "default": []
          },
          "messages": {
            "type": "Message[]",
            "required": false,
            "description": "Atomic message payloads queued for delivery (R20.6 Part 1.2 primitives).",
            "default": []
          },
          "conversations": {
            "type": "Conversation[]",
            "required": false,
            "description": "Multi-party threaded conversations with membership metadata (R20.6 Part 3.3).",
            "default": []
          },
          "message_statuses": {
            "type": "MessageStatusEntry[]",
            "required": false,
            "description": "Delivery state machine transitions (queued → sent → delivered → failed → retried → read).",
            "default": []
          }
        },
        "semantics": {
          "channel_catalog": {
            "semantic_type": "communication.channels",
            "token_mapping": "--sys-communication-accent",
            "ui_hints": {
              "component": "ChannelGrid",
              "badges": "channel_catalog[].type"
            }
          },
          "template_catalog": {
            "semantic_type": "communication.templates",
            "token_mapping": "--sys-communication-muted",
            "ui_hints": {
              "component": "TemplateDrawer",
              "variableBadge": "template_catalog[].variables"
            }
          },
          "delivery_policies": {
            "semantic_type": "communication.delivery_policy",
            "token_mapping": "--sys-communication-accent",
            "ui_hints": {
              "component": "DeliveryPolicyCapsule"
            }
          },
          "messages": {
            "semantic_type": "communication.messages",
            "token_mapping": "--sys-communication-success",
            "ui_hints": {
              "component": "MessageTimeline"
            }
          },
          "conversations": {
            "semantic_type": "communication.conversations",
            "token_mapping": "--sys-communication-accent",
            "ui_hints": {
              "component": "ConversationViewer"
            }
          }
        },
        "tokens": {
          "communication.card.bg": "var(--sys-surface-raised)",
          "communication.card.border": "var(--sys-communication-muted)",
          "communication.status.success": "var(--sys-communication-success)",
          "communication.status.error": "var(--sys-communication-error)"
        },
        "dependencies": [
          "Preferenceable",
          "Authable"
        ],
        "metadata": {
          "created": "2025-11-20",
          "owners": [
            "notifications@oods.systems"
          ],
          "maturity": "experimental",
          "accessibility": {
            "keyboard": "ChannelGrid keeps linear tab stops and roving focus for template previews.",
            "screenreader": "MessageEventTimeline announces delivery transitions with ARIA live updates per R20.6 guidance."
          },
          "regionsUsed": [
            "list",
            "detail",
            "form"
          ],
          "references": [
            "R20.1 Canonical Notification Model",
            "R20.6 Foundational Analysis of Modern Message and Communication Systems"
          ]
        },
        "objects": [
          "Organization",
          "User"
        ],
        "source": "traits/core/Communicable.trait.yaml"
      },
      "EncodingColor": {
        "name": "EncodingColor",
        "version": "0.2.0",
        "description": "Maps a data field to chromatic encodings using governed palettes and\nredundant channels to fulfill RDV.4 accessibility equivalence rules.",
        "category": "viz.encoding",
        "tags": [
          "viz",
          "encoding",
          "color"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "VizEncodingBadge",
            "context": "detail",
            "position": "sidebar",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "channel": "color"
            }
          },
          {
            "component": "VizColorControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "schemeField": "viz_encoding_color_scheme",
              "channelField": "viz_encoding_color_channel",
              "redundancyField": "viz_encoding_color_redundancy",
              "contrastField": "viz_encoding_color_min_contrast"
            }
          },
          {
            "component": "VizColorLegendConfig",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent"
            }
          },
          {
            "component": "VizEncodingBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "channel": "color",
              "axis": "color",
              "fieldField": "viz_encoding_color_field"
            }
          }
        ],
        "parameters": [
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "supportedSchemes",
            "type": "string[]",
            "required": true,
            "description": "Palette categories that this encoding may leverage.",
            "default": [
              "categorical",
              "sequential",
              "diverging"
            ]
          },
          {
            "name": "defaultScheme",
            "type": "string",
            "required": true,
            "description": "Palette category used when author does not specify.",
            "default": "categorical",
            "validation": {
              "enum": [
                "categorical",
                "sequential",
                "diverging"
              ]
            }
          },
          {
            "name": "redundancyMechanism",
            "type": "string",
            "required": true,
            "description": "Non-color fallback used to satisfy equivalence rules.",
            "default": "texture",
            "validation": {
              "enum": [
                "texture",
                "shape",
                "label"
              ]
            }
          },
          {
            "name": "minContrast",
            "type": "number",
            "required": false,
            "description": "Minimum contrast ratio enforced between adjacent categories.",
            "default": 4.5,
            "validation": {
              "minimum": 3,
              "maximum": 7
            }
          },
          {
            "name": "channel",
            "type": "string",
            "required": false,
            "description": "Which graphical channel color touches (fill vs stroke).",
            "default": "fill",
            "validation": {
              "enum": [
                "fill",
                "stroke"
              ]
            }
          }
        ],
        "schema": {
          "viz_encoding_color_field": {
            "type": "string",
            "required": true,
            "description": "Data field bound to chroma."
          },
          "viz_encoding_color_scheme": {
            "type": "string",
            "required": true,
            "description": "Palette category used for this encoding.",
            "defaultFromParameter": "defaultScheme",
            "validation": {
              "enumFromParameter": "supportedSchemes"
            }
          },
          "viz_encoding_color_channel": {
            "type": "string",
            "required": false,
            "description": "Graphical channel that carries color (fill or stroke).",
            "defaultFromParameter": "channel",
            "validation": {
              "enum": [
                "fill",
                "stroke"
              ]
            }
          },
          "viz_encoding_color_redundancy": {
            "type": "string",
            "required": true,
            "description": "Secondary channel used for equivalence (texture, shape, label).",
            "defaultFromParameter": "redundancyMechanism",
            "validation": {
              "enum": [
                "texture",
                "shape",
                "label"
              ]
            }
          },
          "viz_encoding_color_min_contrast": {
            "type": "number",
            "required": false,
            "description": "Minimum enforced contrast ratio between adjacent categories.",
            "defaultFromParameter": "minContrast",
            "validation": {
              "minimum": 3,
              "maximum": 7
            }
          },
          "viz_encoding_color_description": {
            "type": "string",
            "required": false,
            "description": "Natural language summary for fallback narratives.",
            "default": "Uses governed palette with redundant encodings per RDV.4."
          }
        },
        "semantics": {
          "viz_encoding_color_field": {
            "semantic_type": "viz.encoding.field",
            "token_mapping": "tokenMap(viz.encoding.field)",
            "ui_hints": {
              "component": "FieldReference"
            }
          },
          "viz_encoding_color_scheme": {
            "semantic_type": "viz.encoding.palette",
            "token_mapping": "tokenMap(viz.palette.scheme)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_encoding_color_channel": {
            "semantic_type": "viz.encoding.channel",
            "token_mapping": "tokenMap(viz.channel)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_encoding_color_redundancy": {
            "semantic_type": "viz.encoding.redundancy",
            "token_mapping": "tokenMap(viz.redundancy)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_encoding_color_min_contrast": {
            "semantic_type": "viz.encoding.contrast",
            "token_mapping": "tokenMap(viz.a11y.contrast)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "ratio"
            }
          }
        },
        "tokens": {
          "viz.encoding.color.palette.categorical": "var(--cmp-viz-color-categorical)",
          "viz.encoding.color.palette.sequential": "var(--cmp-viz-color-sequential)",
          "viz.encoding.color.palette.diverging": "var(--cmp-viz-color-diverging)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "accessibility@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "rule_reference": "A11Y-R-01",
            "notes": "Requires redundant encoding + 4.5:1 contrast for adjacent hues."
          },
          "regionsUsed": [
            "detail",
            "form",
            "list"
          ],
          "references": [
            "RDV.4 Validation of Accessibility Equivalence in Trait-Driven Visualization Systems",
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/encoding-color.trait.yaml"
      },
      "EncodingOpacity": {
        "name": "EncodingOpacity",
        "version": "0.1.0",
        "description": "Constant Cartesian mark opacity",
        "category": "viz.encoding",
        "tags": [
          "viz",
          "authoring"
        ],
        "contexts": [
          "detail",
          "form"
        ],
        "viewExtensions": [
          {
            "component": "VizOpacityControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent"
            }
          },
          {
            "component": "VizOpacitySummary",
            "context": "detail",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent"
            }
          }
        ],
        "parameters": [
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment; data rows are supplied by the consumer."
          }
        ],
        "schema": {},
        "semantics": {},
        "tokens": {},
        "dependencies": [],
        "metadata": {
          "regionsUsed": [
            "form",
            "detail"
          ]
        },
        "objects": [],
        "source": "traits/viz/encoding-opacity.trait.yaml"
      },
      "EncodingPositionX": {
        "name": "EncodingPositionX",
        "version": "0.2.0",
        "description": "Binds a data field to the horizontal axis. Declares allowed data types,\nscale defaults, and accessibility metadata to satisfy Normalized Viz Spec\nrequirements.",
        "category": "viz.encoding",
        "tags": [
          "viz",
          "encoding",
          "x-axis",
          "position"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "VizAxisSummary",
            "context": "detail",
            "position": "sidebar",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "channel": "x",
              "axis": "x",
              "titleField": "viz_encoding_x_axis_title",
              "scaleField": "viz_encoding_x_scale",
              "zeroField": "viz_encoding_x_include_zero"
            }
          },
          {
            "component": "VizAxisControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "channel": "x",
              "axis": "x",
              "fieldField": "viz_encoding_x_field",
              "kindField": "viz_encoding_x_field_kind",
              "scaleField": "viz_encoding_x_scale",
              "titleField": "viz_encoding_x_axis_title",
              "zeroField": "viz_encoding_x_include_zero",
              "sortField": "viz_encoding_x_sort"
            }
          },
          {
            "component": "VizEncodingBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "channel": "x",
              "axis": "x",
              "fieldField": "viz_encoding_x_field"
            }
          }
        ],
        "parameters": [
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "fieldKinds",
            "type": "string[]",
            "required": true,
            "description": "Data categories that can map to the X axis.",
            "default": [
              "nominal",
              "ordinal",
              "quantitative",
              "temporal"
            ]
          },
          {
            "name": "defaultScale",
            "type": "string",
            "required": true,
            "description": "Default scale used when none is specified by the spec author.",
            "default": "linear",
            "validation": {
              "enum": [
                "linear",
                "temporal"
              ]
            }
          },
          {
            "name": "includeZero",
            "type": "boolean",
            "required": false,
            "description": "Whether quantitative mappings force a zero baseline.",
            "default": true
          },
          {
            "name": "axisTitle",
            "type": "string",
            "required": false,
            "description": "Default title surfaced in axis + a11y description.",
            "default": "X Axis"
          },
          {
            "name": "sorting",
            "type": "string",
            "required": false,
            "description": "Default sort applied to discrete categories.",
            "default": "none",
            "validation": {
              "enum": [
                "none",
                "ascending",
                "descending"
              ]
            }
          }
        ],
        "schema": {
          "viz_encoding_x_field": {
            "type": "string",
            "required": true,
            "description": "Name of the data field bound to the X axis."
          },
          "viz_encoding_x_field_kind": {
            "type": "string",
            "required": true,
            "description": "Data classification used for heuristics and validation.",
            "validation": {
              "enumFromParameter": "fieldKinds"
            }
          },
          "viz_encoding_x_scale": {
            "type": "string",
            "required": true,
            "description": "Scale identifier applied to values (linear or temporal).",
            "defaultFromParameter": "defaultScale",
            "validation": {
              "enum": [
                "linear",
                "temporal"
              ]
            }
          },
          "viz_encoding_x_include_zero": {
            "type": "boolean",
            "required": false,
            "description": "Indicates whether zero baseline enforcement is active.",
            "defaultFromParameter": "includeZero"
          },
          "viz_encoding_x_axis_title": {
            "type": "string",
            "required": false,
            "description": "Default axis title used in UI and fallback descriptions.",
            "defaultFromParameter": "axisTitle"
          },
          "viz_encoding_x_sort": {
            "type": "string",
            "required": false,
            "description": "Default sort direction for discrete axes.",
            "defaultFromParameter": "sorting",
            "validation": {
              "enum": [
                "none",
                "ascending",
                "descending"
              ]
            }
          }
        },
        "semantics": {
          "viz_encoding_x_field": {
            "semantic_type": "viz.encoding.field",
            "token_mapping": "tokenMap(viz.encoding.field)",
            "ui_hints": {
              "component": "FieldReference"
            }
          },
          "viz_encoding_x_field_kind": {
            "semantic_type": "viz.encoding.field_kind",
            "token_mapping": "tokenMap(viz.encoding.field_kind)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_encoding_x_scale": {
            "semantic_type": "viz.encoding.scale",
            "token_mapping": "tokenMap(viz.scale.type)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_encoding_x_axis_title": {
            "semantic_type": "viz.encoding.axis_title",
            "token_mapping": "tokenMap(viz.axis.title)",
            "ui_hints": {
              "component": "TextField"
            }
          },
          "viz_encoding_x_include_zero": {
            "semantic_type": "viz.encoding.zero_baseline",
            "token_mapping": "tokenMap(viz.scale.zero)",
            "ui_hints": {
              "component": "BooleanBadge"
            }
          }
        },
        "tokens": {
          "viz.encoding.x.axis.title": "var(--cmp-text-strong)",
          "viz.encoding.x.axis.tick": "var(--cmp-viz-axis-tick)",
          "viz.encoding.x.axis.line": "var(--cmp-viz-axis-line)"
        },
        "dependencies": [
          "ScaleLinear"
        ],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "engineering@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "rule_reference": "A11Y-R-05",
            "notes": "Provide axis titles + descriptions for assistive tech fallbacks."
          },
          "regionsUsed": [
            "detail",
            "form",
            "list"
          ],
          "allows": [
            "MarkBar",
            "MarkLine",
            "MarkPoint",
            "MarkArea"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/encoding-position-x.trait.yaml"
      },
      "EncodingPositionY": {
        "name": "EncodingPositionY",
        "version": "0.2.0",
        "description": "Binds a data field to the vertical axis. Provides normalization, default\nscale hints, and a11y metadata for describing quantitative measures.",
        "category": "viz.encoding",
        "tags": [
          "viz",
          "encoding",
          "y-axis",
          "position"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "VizAxisSummary",
            "context": "detail",
            "position": "sidebar",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "channel": "y",
              "axis": "y",
              "titleField": "viz_encoding_y_axis_title",
              "scaleField": "viz_encoding_y_scale",
              "zeroField": "viz_encoding_y_include_zero"
            }
          },
          {
            "component": "VizAxisControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "channel": "y",
              "axis": "y",
              "fieldField": "viz_encoding_y_field",
              "kindField": "viz_encoding_y_field_kind",
              "scaleField": "viz_encoding_y_scale",
              "titleField": "viz_encoding_y_axis_title",
              "zeroField": "viz_encoding_y_include_zero",
              "aggregateField": "viz_encoding_y_aggregate"
            }
          },
          {
            "component": "VizEncodingBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "channel": "y",
              "axis": "y",
              "fieldField": "viz_encoding_y_field"
            }
          }
        ],
        "parameters": [
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "fieldKinds",
            "type": "string[]",
            "required": true,
            "description": "Data categories that can map to the Y axis.",
            "default": [
              "quantitative",
              "temporal",
              "ordinal"
            ]
          },
          {
            "name": "defaultScale",
            "type": "string",
            "required": true,
            "description": "Default scale used when not specified explicitly.",
            "default": "linear",
            "validation": {
              "enum": [
                "linear",
                "temporal"
              ]
            }
          },
          {
            "name": "includeZero",
            "type": "boolean",
            "required": false,
            "description": "Whether to enforce zero baseline for quantitative data.",
            "default": true
          },
          {
            "name": "axisTitle",
            "type": "string",
            "required": false,
            "description": "Default title surfaced in UI and fallback descriptions.",
            "default": "Y Axis"
          },
          {
            "name": "aggregate",
            "type": "string",
            "required": false,
            "description": "Default aggregation applied when spec omits one.",
            "default": "sum",
            "validation": {
              "enum": [
                "sum",
                "mean",
                "median",
                "count"
              ]
            }
          }
        ],
        "schema": {
          "viz_encoding_y_field": {
            "type": "string",
            "required": true,
            "description": "Name of the data field bound to the Y axis."
          },
          "viz_encoding_y_field_kind": {
            "type": "string",
            "required": true,
            "description": "Data classification used for heuristics and validation.",
            "validation": {
              "enumFromParameter": "fieldKinds"
            }
          },
          "viz_encoding_y_scale": {
            "type": "string",
            "required": true,
            "description": "Scale identifier applied to the Y axis.",
            "defaultFromParameter": "defaultScale",
            "validation": {
              "enum": [
                "linear",
                "temporal"
              ]
            }
          },
          "viz_encoding_y_include_zero": {
            "type": "boolean",
            "required": false,
            "description": "Indicates whether zero baseline enforcement is active.",
            "defaultFromParameter": "includeZero"
          },
          "viz_encoding_y_axis_title": {
            "type": "string",
            "required": false,
            "description": "Default axis title used in UI and fallback descriptions.",
            "defaultFromParameter": "axisTitle"
          },
          "viz_encoding_y_aggregate": {
            "type": "string",
            "required": false,
            "description": "Aggregation strategy applied when spec omits one.",
            "defaultFromParameter": "aggregate",
            "validation": {
              "enum": [
                "sum",
                "mean",
                "median",
                "count"
              ]
            }
          }
        },
        "semantics": {
          "viz_encoding_y_field": {
            "semantic_type": "viz.encoding.field",
            "token_mapping": "tokenMap(viz.encoding.field)",
            "ui_hints": {
              "component": "FieldReference"
            }
          },
          "viz_encoding_y_field_kind": {
            "semantic_type": "viz.encoding.field_kind",
            "token_mapping": "tokenMap(viz.encoding.field_kind)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_encoding_y_scale": {
            "semantic_type": "viz.encoding.scale",
            "token_mapping": "tokenMap(viz.scale.type)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_encoding_y_axis_title": {
            "semantic_type": "viz.encoding.axis_title",
            "token_mapping": "tokenMap(viz.axis.title)",
            "ui_hints": {
              "component": "TextField"
            }
          },
          "viz_encoding_y_aggregate": {
            "semantic_type": "viz.encoding.aggregate",
            "token_mapping": "tokenMap(viz.aggregate)",
            "ui_hints": {
              "component": "TextBadge"
            }
          }
        },
        "tokens": {
          "viz.encoding.y.axis.title": "var(--cmp-text-strong)",
          "viz.encoding.y.axis.tick": "var(--cmp-viz-axis-tick)",
          "viz.encoding.y.axis.line": "var(--cmp-viz-axis-line)"
        },
        "dependencies": [
          "ScaleLinear"
        ],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "engineering@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "rule_reference": "A11Y-R-05",
            "notes": "Axis title doubles as descriptive label in fallback tables."
          },
          "regionsUsed": [
            "detail",
            "form",
            "list"
          ],
          "allows": [
            "MarkBar",
            "MarkLine",
            "MarkPoint",
            "MarkArea"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/encoding-position-y.trait.yaml"
      },
      "EncodingShape": {
        "name": "EncodingShape",
        "version": "0.1.0",
        "description": "Categorical shape encoding",
        "category": "viz.encoding",
        "tags": [
          "viz",
          "authoring"
        ],
        "contexts": [
          "form"
        ],
        "viewExtensions": [
          {
            "component": "VizShapeControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent"
            }
          },
          {
            "component": "VizShapeLegend",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent"
            }
          }
        ],
        "parameters": [
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment; data rows are supplied by the consumer."
          }
        ],
        "schema": {},
        "semantics": {},
        "tokens": {},
        "dependencies": [],
        "metadata": {
          "regionsUsed": [
            "form"
          ]
        },
        "objects": [],
        "source": "traits/viz/encoding-shape.trait.yaml"
      },
      "EncodingSize": {
        "name": "EncodingSize",
        "version": "0.2.0",
        "description": "Maps a quantitative field to glyph size (radius or area) with governed\nranges that can be validated for perceptual correctness and accessibility.",
        "category": "viz.encoding",
        "tags": [
          "viz",
          "encoding",
          "size"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "VizSizeSummary",
            "context": "detail",
            "position": "sidebar",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "field": "viz_encoding_size_field",
              "strategyField": "viz_encoding_size_strategy",
              "minField": "viz_encoding_size_range_min",
              "maxField": "viz_encoding_size_range_max"
            }
          },
          {
            "component": "VizSizeControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "strategyField": "viz_encoding_size_strategy",
              "minField": "viz_encoding_size_range_min",
              "maxField": "viz_encoding_size_range_max",
              "minAreaField": "viz_encoding_size_min_area",
              "maxAreaField": "viz_encoding_size_max_area"
            }
          },
          {
            "component": "VizEncodingBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "channel": "size",
              "axis": "size",
              "fieldField": "viz_encoding_size_field"
            }
          }
        ],
        "parameters": [
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "rangeMin",
            "type": "number",
            "required": true,
            "description": "Minimum rendered size in device-independent pixels.",
            "default": 6,
            "validation": {
              "minimum": 2,
              "maximum": 32
            }
          },
          {
            "name": "rangeMax",
            "type": "number",
            "required": true,
            "description": "Maximum rendered size in device-independent pixels.",
            "default": 36,
            "validation": {
              "minimum": 12,
              "maximum": 96
            }
          },
          {
            "name": "strategy",
            "type": "string",
            "required": true,
            "description": "Interprets values as area or radius for perceptual scaling.",
            "default": "area",
            "validation": {
              "enum": [
                "area",
                "radius"
              ]
            }
          },
          {
            "name": "minPixelArea",
            "type": "number",
            "required": false,
            "description": "Minimum accessible area to avoid disappearing glyphs.",
            "default": 36
          },
          {
            "name": "maxPixelArea",
            "type": "number",
            "required": false,
            "description": "Maximum accessible area to avoid dominating layout.",
            "default": 576
          }
        ],
        "schema": {
          "viz_encoding_size_field": {
            "type": "string",
            "required": true,
            "description": "Data field bound to glyph size."
          },
          "viz_encoding_size_strategy": {
            "type": "string",
            "required": true,
            "description": "Defines whether size is derived from area or radius.",
            "defaultFromParameter": "strategy",
            "validation": {
              "enum": [
                "area",
                "radius"
              ]
            }
          },
          "viz_encoding_size_range_min": {
            "type": "number",
            "required": true,
            "description": "Minimum rendered size in pixels.",
            "defaultFromParameter": "rangeMin"
          },
          "viz_encoding_size_range_max": {
            "type": "number",
            "required": true,
            "description": "Maximum rendered size in pixels.",
            "defaultFromParameter": "rangeMax"
          },
          "viz_encoding_size_min_area": {
            "type": "number",
            "required": false,
            "description": "Minimum accessible area to prevent underflow.",
            "defaultFromParameter": "minPixelArea"
          },
          "viz_encoding_size_max_area": {
            "type": "number",
            "required": false,
            "description": "Maximum accessible area to prevent overflow.",
            "defaultFromParameter": "maxPixelArea"
          },
          "viz_encoding_size_description": {
            "type": "string",
            "required": false,
            "description": "Narrative summary for fallback text/table output.",
            "default": "Size encodes magnitude using governed perceptual scaling."
          }
        },
        "semantics": {
          "viz_encoding_size_field": {
            "semantic_type": "viz.encoding.field",
            "token_mapping": "tokenMap(viz.encoding.field)",
            "ui_hints": {
              "component": "FieldReference"
            }
          },
          "viz_encoding_size_strategy": {
            "semantic_type": "viz.encoding.size_strategy",
            "token_mapping": "tokenMap(viz.encoding.size_strategy)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_encoding_size_range_min": {
            "semantic_type": "viz.encoding.size_range",
            "token_mapping": "tokenMap(viz.encoding.size_range)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "px"
            }
          },
          "viz_encoding_size_range_max": {
            "semantic_type": "viz.encoding.size_range",
            "token_mapping": "tokenMap(viz.encoding.size_range)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "px"
            }
          },
          "viz_encoding_size_min_area": {
            "semantic_type": "viz.encoding.a11y_min",
            "token_mapping": "tokenMap(viz.a11y.min_target)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "px^2"
            }
          }
        },
        "tokens": {
          "viz.encoding.size.range.min": "var(--cmp-viz-size-min)",
          "viz.encoding.size.range.max": "var(--cmp-viz-size-max)",
          "viz.encoding.size.stroke": "var(--cmp-viz-size-stroke)"
        },
        "dependencies": [
          "ScaleLinear"
        ],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "research@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "rule_reference": "A11Y-R-02",
            "notes": "Ensures glyphs remain perceivable within governed range."
          },
          "regionsUsed": [
            "detail",
            "form",
            "list"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/encoding-size.trait.yaml"
      },
      "Filterable": {
        "name": "Filterable",
        "version": "1.0.0",
        "description": "Adds multi-facet filtering to list and collection views. Filterable injects a filter panel\ninto the sidebar or header region, wires filter state to the data layer, and provides\nsemantic token mappings for consistent filter UI styling across brands.\n\nFilters are defined as an array of filter descriptors, each specifying a field, operator,\nand available values. Active filters are tracked separately for apply/clear lifecycle.\nThe trait supports both immediate-apply and batch-apply modes for UX flexibility.",
        "category": "behavioral",
        "tags": [
          "filtering",
          "facets",
          "list-behavior",
          "data-refinement"
        ],
        "contexts": [
          "detail",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "FilterPanel",
            "context": "list",
            "position": "sidebar",
            "priority": 8,
            "props": {
              "field": "filters",
              "activeField": "activeFilters",
              "modeParameter": "filterMode",
              "maxActiveParameter": "maxActiveFilters",
              "collapsibleParameter": "collapsible"
            }
          },
          {
            "component": "FilterPanel",
            "context": "detail",
            "position": "sidebar",
            "priority": 8,
            "props": {
              "field": "filters",
              "activeField": "activeFilters",
              "modeParameter": "filterMode",
              "collapsibleParameter": "collapsible"
            }
          }
        ],
        "parameters": [
          {
            "name": "filterMode",
            "type": "string",
            "required": false,
            "description": "Controls when filter changes take effect:\n- immediate: Filters apply as soon as the user changes a value.\n- batch: Filters accumulate until the user clicks an explicit \"Apply\" button.\n",
            "default": "immediate",
            "validation": {
              "enum": [
                "immediate",
                "batch"
              ]
            }
          },
          {
            "name": "maxActiveFilters",
            "type": "number",
            "required": false,
            "description": "Maximum number of simultaneous active filters. 0 means unlimited.",
            "default": 0,
            "validation": {
              "minimum": 0,
              "maximum": 50
            }
          },
          {
            "name": "showFilterCount",
            "type": "boolean",
            "required": false,
            "description": "Whether to display a badge showing the number of active filters.",
            "default": true
          },
          {
            "name": "collapsible",
            "type": "boolean",
            "required": false,
            "description": "Whether filter panel sections can be collapsed individually.",
            "default": true
          }
        ],
        "schema": {
          "filters": {
            "type": "object[]",
            "required": false,
            "description": "Array of available filter descriptors. Each entry defines a filterable dimension:\n  - field: string (the schema field to filter on)\n  - label: string (display label)\n  - type: \"select\" | \"multi-select\" | \"range\" | \"boolean\" | \"date-range\"\n  - options: array of { value, label } for select/multi-select types\n",
            "default": []
          },
          "activeFilters": {
            "type": "object[]",
            "required": false,
            "description": "Array of currently applied filter values:\n  - field: string (matches a filter descriptor field)\n  - operator: \"eq\" | \"in\" | \"range\" | \"gt\" | \"lt\" | \"between\"\n  - value: unknown (the selected filter value or values)\n",
            "default": []
          },
          "filterCount": {
            "type": "number",
            "required": true,
            "description": "Computed count of currently active filters.",
            "default": 0,
            "validation": {
              "minimum": 0
            }
          }
        },
        "semantics": {
          "filters": {
            "semantic_type": "input.filter.descriptors",
            "token_mapping": "tokenMap(filter.panel.*)",
            "ui_hints": {
              "component": "FilterPanel",
              "modeParameter": "filterMode"
            }
          },
          "activeFilters": {
            "semantic_type": "state.filter.active",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "FilterPanel",
              "description": "Drives active filter chip display and clear actions."
            }
          },
          "filterCount": {
            "semantic_type": "metric.filter.count",
            "token_mapping": "tokenMap(filter.badge.*)",
            "ui_hints": {
              "component": "MetricBadge",
              "format": "integer"
            }
          }
        },
        "tokens": {
          "filter.panel.bg": "var(--sys-surface-secondary)",
          "filter.panel.border": "var(--sys-border-default)",
          "filter.panel.header.text": "var(--sys-text-primary)",
          "filter.panel.section.divider": "var(--sys-border-subtle)",
          "filter.chip.bg": "var(--sys-surface-accent)",
          "filter.chip.text": "var(--sys-text-on-accent)",
          "filter.chip.remove.hover": "var(--sys-surface-hover)",
          "filter.badge.bg": "var(--sys-surface-accent)",
          "filter.badge.text": "var(--sys-text-on-accent)",
          "filter.apply.bg": "var(--sys-action-primary)",
          "filter.apply.text": "var(--sys-text-on-action)",
          "filter.clear.text": "var(--sys-text-subtle)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2026-03-05",
          "updated": "2026-03-06",
          "owners": [
            "design@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "FilterPanel supports full keyboard navigation:\n- Tab to move between filter controls\n- Enter/Space to toggle selections\n- Escape to collapse an open dropdown\n- In batch mode, Tab to Apply button, Enter to submit\n",
            "screenreader": "Filter panel is announced with role=\"region\" and aria-label=\"Filters\".\nActive filter changes are announced via aria-live when filters change.\nClear-all button is announced as \"Clear all filters\".\n"
          },
          "regionsUsed": [
            "list",
            "detail"
          ],
          "examples": [
            "Product catalog filtering",
            "Invoice list filtering",
            "User management filtering"
          ],
          "references": [
            "Trait Engine Spec v0.1 section 2"
          ]
        },
        "objects": [
          "Product"
        ],
        "source": "traits/behavioral/Filterable.trait.yaml"
      },
      "Geocodable": {
        "name": "Geocodable",
        "version": "1.0.1",
        "description": "Indicates that data contains location-resolvable information that can be\nmapped to coordinates or geographic boundaries. Supports auto-detection\nof geo fields based on naming patterns and field types.",
        "category": "viz.spatial",
        "tags": [
          "viz",
          "spatial",
          "geo",
          "location",
          "map"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "GeocodablePreview",
            "context": "detail",
            "position": "top",
            "priority": 70,
            "props": {
              "resolutionField": "geo_resolution",
              "requiresLookupField": "geo_requires_lookup",
              "detectedFieldsField": "geo_detected_fields"
            }
          },
          {
            "component": "GeoFieldMappingForm",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "latitudeField": "geo_latitude_field",
              "longitudeField": "geo_longitude_field",
              "identifierField": "geo_identifier_field",
              "autoDetectField": "geo_auto_detect_enabled"
            }
          },
          {
            "component": "GeoResolutionBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "resolutionField": "geo_resolution"
            }
          }
        ],
        "parameters": [
          {
            "name": "autoDetect",
            "type": "boolean",
            "required": false,
            "description": "Enable automatic detection of geo fields based on naming patterns.",
            "default": true
          },
          {
            "name": "explicitFields",
            "type": "string[]",
            "required": false,
            "description": "Explicitly specify which fields contain geographic data.",
            "default": []
          },
          {
            "name": "minConfidence",
            "type": "number",
            "required": false,
            "description": "Minimum confidence threshold for auto-detected fields (0-1).",
            "default": 0.7,
            "validation": {
              "minimum": 0,
              "maximum": 1
            }
          }
        ],
        "schema": {
          "geo_resolution": {
            "type": "string",
            "required": true,
            "description": "Type of geographic resolution available (point, boundary, or both).",
            "default": "point",
            "validation": {
              "enum": [
                "point",
                "boundary",
                "both"
              ]
            }
          },
          "geo_requires_lookup": {
            "type": "boolean",
            "required": true,
            "description": "Whether geographic identifiers require lookup to resolve.",
            "default": false
          },
          "geo_detected_fields": {
            "type": "object[]",
            "required": false,
            "description": "Array of detected geo fields with type and confidence.",
            "default": []
          },
          "geo_latitude_field": {
            "type": "string",
            "required": false,
            "description": "Field name containing latitude values (for point resolution)."
          },
          "geo_longitude_field": {
            "type": "string",
            "required": false,
            "description": "Field name containing longitude values (for point resolution)."
          },
          "geo_identifier_field": {
            "type": "string",
            "required": false,
            "description": "Primary field name containing geographic identifiers."
          },
          "geo_identifier_type": {
            "type": "string",
            "required": false,
            "description": "Type of geographic identifier (e.g., country, state, fips)."
          },
          "geo_auto_detect_enabled": {
            "type": "boolean",
            "required": true,
            "description": "Whether auto-detection of geo fields is enabled.",
            "default": true
          }
        },
        "semantics": {
          "geo_resolution": {
            "semantic_type": "viz.spatial.resolution",
            "token_mapping": "tokenMap(viz.spatial.resolution)",
            "ui_hints": {
              "component": "GeoResolutionBadge"
            }
          },
          "geo_requires_lookup": {
            "semantic_type": "viz.spatial.lookup",
            "token_mapping": "tokenMap(viz.spatial.lookup)",
            "ui_hints": {
              "component": "BooleanIndicator",
              "label_when_true": "Requires geocoding",
              "label_when_false": "Direct coordinates"
            }
          },
          "geo_detected_fields": {
            "semantic_type": "viz.spatial.detected_fields",
            "ui_hints": {
              "component": "GeoFieldList"
            }
          },
          "geo_latitude_field": {
            "semantic_type": "viz.spatial.coordinate.lat",
            "ui_hints": {
              "component": "FieldSelector",
              "filter": "numeric"
            }
          },
          "geo_longitude_field": {
            "semantic_type": "viz.spatial.coordinate.lon",
            "ui_hints": {
              "component": "FieldSelector",
              "filter": "numeric"
            }
          },
          "geo_identifier_field": {
            "semantic_type": "viz.spatial.identifier",
            "ui_hints": {
              "component": "FieldSelector",
              "filter": "string"
            }
          },
          "geo_identifier_type": {
            "semantic_type": "viz.spatial.identifier_type",
            "ui_hints": {
              "component": "GeoIdentifierTypeSelector"
            }
          }
        },
        "tokens": {
          "viz.spatial.geocodable.icon": "var(--cmp-viz-spatial-geocodable-icon)",
          "viz.spatial.geocodable.badge.point": "var(--cmp-viz-spatial-badge-point)",
          "viz.spatial.geocodable.badge.boundary": "var(--cmp-viz-spatial-badge-boundary)",
          "viz.spatial.geocodable.badge.both": "var(--cmp-viz-spatial-badge-both)",
          "viz.spatial.geocodable.confidence.high": "var(--cmp-viz-spatial-confidence-high)",
          "viz.spatial.geocodable.confidence.medium": "var(--cmp-viz-spatial-confidence-medium)",
          "viz.spatial.geocodable.confidence.low": "var(--cmp-viz-spatial-confidence-low)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-29",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "spatial@oods.systems"
          ],
          "maturity": "alpha",
          "conflicts_with": [],
          "accessibility": {
            "rule_reference": "A11Y-R-04",
            "notes": "Spatial visualizations require table fallback with region/coordinate data."
          },
          "regionsUsed": [
            "detail",
            "form",
            "list"
          ],
          "examples": [
            "SalesByState",
            "StoreLocations",
            "PopulationByCountry"
          ],
          "references": [
            "Spatial module architecture (data-viz part 2)",
            "RV.03 Gap Analysis"
          ]
        },
        "objects": [],
        "source": "traits/viz/spatial/geocodable.trait.yaml"
      },
      "InteractionHighlight": {
        "name": "InteractionHighlight",
        "version": "0.2.0",
        "description": "Emphasizes hovered or selected points by adjusting a configurable visual property.",
        "category": "viz.interaction",
        "tags": [
          "viz",
          "interaction",
          "highlight"
        ],
        "contexts": [],
        "viewExtensions": [],
        "parameters": [
          {
            "name": "fields",
            "type": "string[]",
            "required": true,
            "description": "Data fields that define the highlight predicate."
          },
          {
            "name": "trigger",
            "type": "string",
            "required": false,
            "description": "Event stream that activates the highlight.",
            "default": "hover",
            "validation": {
              "enum": [
                "hover",
                "click",
                "focus"
              ]
            }
          },
          {
            "name": "property",
            "type": "string",
            "required": false,
            "description": "Visual property to adjust when the predicate is active.",
            "default": "fillOpacity"
          },
          {
            "name": "activeValue",
            "type": "number",
            "required": false,
            "description": "Value applied to highlighted marks.",
            "default": 1,
            "validation": {
              "minimum": 0,
              "maximum": 1
            }
          },
          {
            "name": "inactiveValue",
            "type": "number",
            "required": false,
            "description": "Value applied to non-highlighted marks.",
            "default": 0.35,
            "validation": {
              "minimum": 0,
              "maximum": 1
            }
          }
        ],
        "schema": {
          "viz_interaction_highlight_fields": {
            "type": "string[]",
            "required": true,
            "description": "Fields copied into the interaction predicate."
          },
          "viz_interaction_highlight_trigger": {
            "type": "string",
            "required": true,
            "description": "Event stream used for highlight activation.",
            "defaultFromParameter": "trigger",
            "validation": {
              "enum": [
                "hover",
                "click",
                "focus"
              ]
            }
          },
          "viz_interaction_highlight_property": {
            "type": "string",
            "required": true,
            "description": "Visual property that is conditionally modified.",
            "defaultFromParameter": "property"
          },
          "viz_interaction_highlight_active_value": {
            "type": "number",
            "required": true,
            "description": "Value applied when the predicate matches.",
            "defaultFromParameter": "activeValue",
            "validation": {
              "minimum": 0,
              "maximum": 1
            }
          },
          "viz_interaction_highlight_inactive_value": {
            "type": "number",
            "required": true,
            "description": "Value applied when the predicate does not match.",
            "defaultFromParameter": "inactiveValue",
            "validation": {
              "minimum": 0,
              "maximum": 1
            }
          }
        },
        "semantics": {
          "viz_interaction_highlight_fields": {
            "semantic_type": "viz.interaction.fields",
            "ui_hints": {
              "component": "ListSummary"
            }
          },
          "viz_interaction_highlight_trigger": {
            "semantic_type": "viz.interaction.trigger",
            "ui_hints": {
              "component": "Badge"
            }
          },
          "viz_interaction_highlight_property": {
            "semantic_type": "viz.interaction.property",
            "ui_hints": {
              "component": "Code"
            }
          },
          "viz_interaction_highlight_active_value": {
            "semantic_type": "viz.interaction.value_active",
            "ui_hints": {
              "component": "NumericPreview"
            }
          },
          "viz_interaction_highlight_inactive_value": {
            "semantic_type": "viz.interaction.value_inactive",
            "ui_hints": {
              "component": "NumericPreview"
            }
          }
        },
        "tokens": {
          "viz.interaction.highlight.active.opacity": "var(--cmp-viz-highlight-active-opacity)",
          "viz.interaction.highlight.inactive.opacity": "var(--cmp-viz-highlight-inactive-opacity)",
          "viz.interaction.highlight.outline": "var(--cmp-viz-highlight-outline)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "accessibility@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "keyboard": "Highlight is activatable via keyboard focus (trigger=focus) in addition to\nhover and click. Arrow keys navigate between data points. Enter/Space\ntoggles persistent highlight on click-triggered interactions.\n",
            "screenreader": "When a mark is highlighted, the screen reader announces the datum values\nand indicates it is selected. Non-highlighted marks are announced as\n\"dimmed\" or \"inactive\" to convey the visual distinction.\n",
            "focusManagement": "Focus ring is rendered around the highlighted mark. When highlight clears,\nfocus remains on the last interacted mark.\n"
          },
          "examples": [
            "ScatterplotBrushHighlight",
            "BarChartCategoryHighlight"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/interaction-highlight.trait.yaml"
      },
      "InteractionTooltip": {
        "name": "InteractionTooltip",
        "version": "0.2.0",
        "description": "Shows contextual details-on-demand when focusing or hovering a specific datum.",
        "category": "viz.interaction",
        "tags": [
          "viz",
          "interaction",
          "tooltip"
        ],
        "contexts": [],
        "viewExtensions": [],
        "parameters": [
          {
            "name": "fields",
            "type": "string[]",
            "required": true,
            "description": "Ordered field list rendered inside the tooltip."
          },
          {
            "name": "trigger",
            "type": "string",
            "required": false,
            "description": "Event stream that reveals the tooltip.",
            "default": "hover",
            "validation": {
              "enum": [
                "hover",
                "focus"
              ]
            }
          },
          {
            "name": "alignment",
            "type": "string",
            "required": false,
            "description": "Preferred tooltip alignment around the data point.",
            "default": "auto",
            "validation": {
              "enum": [
                "auto",
                "top",
                "bottom",
                "left",
                "right"
              ]
            }
          }
        ],
        "schema": {
          "viz_interaction_tooltip_fields": {
            "type": "string[]",
            "required": true,
            "description": "Fields surfaced inside the tooltip."
          },
          "viz_interaction_tooltip_trigger": {
            "type": "string",
            "required": true,
            "description": "Event stream used to reveal the tooltip.",
            "defaultFromParameter": "trigger",
            "validation": {
              "enum": [
                "hover",
                "focus"
              ]
            }
          },
          "viz_interaction_tooltip_alignment": {
            "type": "string",
            "required": false,
            "description": "Preferred tooltip alignment token.",
            "defaultFromParameter": "alignment",
            "validation": {
              "enum": [
                "auto",
                "top",
                "bottom",
                "left",
                "right"
              ]
            }
          }
        },
        "semantics": {
          "viz_interaction_tooltip_fields": {
            "semantic_type": "viz.interaction.fields",
            "ui_hints": {
              "component": "ListSummary"
            }
          },
          "viz_interaction_tooltip_trigger": {
            "semantic_type": "viz.interaction.trigger",
            "ui_hints": {
              "component": "Badge"
            }
          },
          "viz_interaction_tooltip_alignment": {
            "semantic_type": "viz.interaction.tooltip.alignment",
            "ui_hints": {
              "component": "Badge"
            }
          }
        },
        "tokens": {
          "viz.interaction.tooltip.bg": "var(--cmp-viz-tooltip-bg)",
          "viz.interaction.tooltip.text": "var(--cmp-viz-tooltip-text)",
          "viz.interaction.tooltip.border": "var(--cmp-viz-tooltip-border)",
          "viz.interaction.tooltip.shadow": "var(--cmp-viz-tooltip-shadow)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "accessibility@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "keyboard": "Tooltip is triggered on focus (not just hover) to support keyboard-only users.\nEscape dismisses the tooltip. Tooltip content is not focusable — it is read-only\nsupplementary information announced by the screen reader.\n",
            "screenreader": "Tooltip content is exposed via aria-describedby on the focused datum.\nScreen readers announce the tooltip fields in declared order when the\ndatum receives focus.\n",
            "focusManagement": "Focus remains on the data mark, not the tooltip. The tooltip is a non-modal\noverlay that follows the focused element. Dismissal returns no focus change.\n"
          },
          "examples": [
            "RevenueByRegionTooltip",
            "UserActivityHoverDetail"
          ],
          "references": [
            "WCAG 2.1 SC 1.4.13 — Content on Hover or Focus",
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/interaction-tooltip.trait.yaml"
      },
      "Labelled": {
        "name": "Labelled",
        "version": "2.0.0",
        "description": "Canonical label, description, and placeholder copy for authored objects.\nLabelled is a foundational content trait used by Organization, Product,\nRelationship, and other core objects to provide consistent text display\nacross all view contexts.\n\nSupports configurable length constraints, required/optional description,\nand copy variants (e.g., primary, short, formal) for context-sensitive\ntext rendering.",
        "category": "content",
        "tags": [
          "label",
          "description",
          "copy",
          "metadata",
          "content"
        ],
        "contexts": [
          "card",
          "detail",
          "form",
          "inline",
          "list",
          "timeline"
        ],
        "viewExtensions": [
          {
            "component": "LabelCell",
            "context": "list",
            "position": null,
            "priority": 100,
            "props": {
              "field": "label",
              "descriptionField": "description",
              "truncate": true,
              "maxLengthParameter": "maxLabelLength"
            }
          },
          {
            "component": "DetailHeader",
            "context": "detail",
            "position": "top",
            "priority": 100,
            "props": {
              "titleField": "label",
              "subtitleField": "description",
              "headingLevel": 1
            }
          },
          {
            "component": "FormLabelGroup",
            "context": "form",
            "position": "before",
            "priority": 100,
            "props": {
              "labelField": "label",
              "descriptionField": "description",
              "placeholderField": "placeholder",
              "maxLabelLengthParameter": "maxLabelLength",
              "maxDescriptionLengthParameter": "maxDescriptionLength",
              "requireDescriptionParameter": "requireDescription"
            }
          },
          {
            "component": "CardHeader",
            "context": "card",
            "position": "top",
            "priority": 100,
            "props": {
              "titleField": "label",
              "supportingField": "description"
            }
          },
          {
            "component": "TimelineEntryLabel",
            "context": "timeline",
            "position": null,
            "priority": null,
            "props": {
              "field": "label",
              "compact": true
            }
          },
          {
            "component": "InlineLabel",
            "context": "inline",
            "position": null,
            "priority": null,
            "props": {
              "field": "label",
              "maxLength": 40
            }
          }
        ],
        "parameters": [
          {
            "name": "maxLabelLength",
            "type": "number",
            "required": false,
            "description": "Maximum character length for the label field. Enforced at schema validation and echoed to UI components for truncation.",
            "default": 80,
            "validation": {
              "minimum": 1,
              "maximum": 255
            }
          },
          {
            "name": "maxDescriptionLength",
            "type": "number",
            "required": false,
            "description": "Maximum character length for the description field. Controls form input limits and detail view truncation.",
            "default": 160,
            "validation": {
              "minimum": 1,
              "maximum": 1000
            }
          },
          {
            "name": "requireDescription",
            "type": "boolean",
            "required": false,
            "description": "When true, description becomes a required field. Useful for objects\nwhere supporting text is essential (e.g., Knowledge Articles).\n",
            "default": false
          },
          {
            "name": "copyVariants",
            "type": "string[]",
            "required": false,
            "description": "Named copy variants available for context-sensitive rendering.\n\"primary\" is the default label. Additional variants (e.g., \"short\", \"formal\")\ncan be used for list truncation, exports, or formal documents.\n",
            "default": [
              "primary"
            ]
          }
        ],
        "schema": {
          "label": {
            "type": "string",
            "required": true,
            "description": "Human-readable display name rendered in primary surfaces.",
            "validation": {
              "minLength": 1,
              "maxLengthFromParameter": "maxLabelLength",
              "pattern": "^\\S.*\\S$|^\\S$"
            }
          },
          "description": {
            "type": "string",
            "required": false,
            "requiredFromParameter": "requireDescription",
            "description": "Supporting description used in detail and card contexts.",
            "validation": {
              "maxLengthFromParameter": "maxDescriptionLength"
            }
          },
          "placeholder": {
            "type": "string",
            "required": false,
            "description": "Hint copy surfaced in form fields when the label is empty.",
            "validation": {
              "maxLength": 80
            }
          }
        },
        "semantics": {
          "label": {
            "semantic_type": "text.label",
            "token_mapping": "tokenMap(text.label.*)",
            "ui_hints": {
              "component": "TextHeading",
              "maxLengthParameter": "maxLabelLength",
              "headingLevel": 2
            }
          },
          "description": {
            "semantic_type": "text.description",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "TextBody",
              "maxLengthParameter": "maxDescriptionLength"
            }
          },
          "placeholder": {
            "semantic_type": "text.placeholder",
            "token_mapping": "tokenMap(text.placeholder.*)",
            "ui_hints": {
              "component": "FormHint",
              "maxLength": 80
            }
          }
        },
        "tokens": {
          "text.label.color": "var(--sys-text-strong)",
          "text.label.font-weight": "var(--sys-font-weight-semibold)",
          "text.label.font-size": "var(--sys-font-size-lg)",
          "text.label.line-height": "var(--sys-line-height-tight)",
          "text.body.color": "var(--sys-text-subtle)",
          "text.body.font-weight": "var(--sys-font-weight-regular)",
          "text.body.font-size": "var(--sys-font-size-sm)",
          "text.body.line-height": "var(--sys-line-height-relaxed)",
          "text.placeholder.color": "var(--sys-text-muted)",
          "text.placeholder.font-weight": "var(--sys-font-weight-regular)",
          "text.placeholder.font-size": "var(--sys-font-size-sm)",
          "text.placeholder.line-height": "var(--sys-line-height-normal)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-10-12",
          "updated": "2026-02-28",
          "owners": [
            "design@oods.systems",
            "uxcopy@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "FormLabelGroup fields are focusable in reading order with standard tab navigation.",
            "screenreader": "Label is announced as a heading (level configurable via headingLevel prop).\nDescription is announced as supplementary text associated with the heading.\nPlaceholder is announced as input hint via aria-placeholder.\n"
          },
          "regionsUsed": [
            "list",
            "detail",
            "form",
            "card",
            "timeline",
            "inline"
          ],
          "examples": [
            "Organization",
            "Product",
            "Relationship",
            "Ticket",
            "Knowledge Article"
          ],
          "references": [
            "Trait Engine Spec v0.1 §2 — foundational trait definitions",
            "objects/core/Organization.object.yaml — consumer",
            "objects/core/Product.object.yaml — consumer",
            "objects/core/Relationship.object.yaml — consumer"
          ]
        },
        "objects": [
          "Article",
          "Media",
          "Organization",
          "Product",
          "Relationship"
        ],
        "source": "traits/content/Labelled.trait.yaml"
      },
      "LayoutConcat": {
        "name": "LayoutConcat",
        "version": "0.2.0",
        "description": "Defines dashboard-style concatenation for coordinated multi-view experiences.",
        "category": "viz.layout",
        "tags": [
          "viz",
          "layout",
          "concat",
          "dashboard"
        ],
        "contexts": [],
        "viewExtensions": [],
        "parameters": [
          {
            "name": "direction",
            "type": "string",
            "required": false,
            "description": "Primary axis used to arrange concatenated sections.",
            "default": "horizontal",
            "validation": {
              "enum": [
                "horizontal",
                "vertical",
                "grid"
              ]
            }
          },
          {
            "name": "gap",
            "type": "number",
            "required": false,
            "description": "Gap (px) between concatenated sections.",
            "default": 24,
            "validation": {
              "minimum": 0,
              "maximum": 96
            }
          },
          {
            "name": "sharedChannels",
            "type": "string[]",
            "required": false,
            "description": "Channels propagated across concatenated children.",
            "default": [
              "color"
            ]
          },
          {
            "name": "maxSections",
            "type": "number",
            "required": false,
            "description": "Maximum number of child sections governed by this layout.",
            "default": 4,
            "validation": {
              "minimum": 2,
              "maximum": 12
            }
          },
          {
            "name": "projection",
            "type": "string",
            "required": false,
            "description": "Projection hint consumed by adapters.",
            "default": "cartesian",
            "validation": {
              "enum": [
                "cartesian",
                "polar",
                "radial"
              ]
            }
          }
        ],
        "schema": {
          "viz_layout_type": {
            "type": "string",
            "required": true,
            "description": "Normalized layout identifier.",
            "default": "concat",
            "validation": {
              "enum": [
                "concat"
              ]
            }
          },
          "viz_layout_direction": {
            "type": "string",
            "required": false,
            "description": "Axis used for arranging concatenated sections.",
            "defaultFromParameter": "direction",
            "validation": {
              "enum": [
                "horizontal",
                "vertical",
                "grid"
              ]
            }
          },
          "viz_layout_gap": {
            "type": "number",
            "required": false,
            "description": "Gap (px) between concatenated sections.",
            "defaultFromParameter": "gap",
            "validation": {
              "minimum": 0,
              "maximum": 96
            }
          },
          "viz_layout_shared_channels": {
            "type": "string[]",
            "required": false,
            "description": "Channels whose domains remain shared across sections.",
            "defaultFromParameter": "sharedChannels"
          },
          "viz_layout_max_sections": {
            "type": "number",
            "required": false,
            "description": "Maximum section count before warning triggers.",
            "defaultFromParameter": "maxSections",
            "validation": {
              "minimum": 2,
              "maximum": 12
            }
          },
          "viz_layout_projection": {
            "type": "string",
            "required": false,
            "description": "Projection metadata forwarded to adapters.",
            "defaultFromParameter": "projection",
            "validation": {
              "enum": [
                "cartesian",
                "polar",
                "radial"
              ]
            }
          }
        },
        "semantics": {
          "viz_layout_type": {
            "semantic_type": "viz.layout.type",
            "ui_hints": {
              "component": "Badge"
            }
          },
          "viz_layout_direction": {
            "semantic_type": "viz.layout.concat.direction",
            "ui_hints": {
              "component": "Badge"
            }
          },
          "viz_layout_gap": {
            "semantic_type": "viz.layout.spacing",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "px"
            }
          },
          "viz_layout_shared_channels": {
            "semantic_type": "viz.layout.shared_channels",
            "ui_hints": {
              "component": "ListSummary"
            }
          },
          "viz_layout_max_sections": {
            "semantic_type": "viz.layout.concat.sections",
            "ui_hints": {
              "component": "NumericPreview"
            }
          },
          "viz_layout_projection": {
            "semantic_type": "viz.layout.projection",
            "ui_hints": {
              "component": "Badge"
            }
          }
        },
        "tokens": {
          "viz.layout.concat.gap": "var(--cmp-viz-layout-gap)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-16",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems"
          ],
          "maturity": "beta",
          "accessibility": {
            "keyboard": "Concatenated sections are keyboard-navigable as a section group. Tab moves between sections.",
            "screenreader": "Announces section count and shared channels (e.g., \"Dashboard with 3 sections, shared color scale\")."
          },
          "examples": [
            "RevenueDashboard",
            "SupportMetricsOverview",
            "SalesFunnelWithBreakdown"
          ],
          "references": [
            "objects/provenance.v1.json#/references/ref-c52ae10b7f25"
          ]
        },
        "objects": [],
        "source": "traits/viz/layout-concat.trait.yaml"
      },
      "LayoutFacet": {
        "name": "LayoutFacet",
        "version": "0.2.0",
        "description": "Repeats a normalized visualization spec across a governed facet grid so row and column groupings stay synchronized with shared color/scale semantics.",
        "category": "viz.layout",
        "tags": [
          "viz",
          "layout",
          "facet",
          "grid"
        ],
        "contexts": [],
        "viewExtensions": [],
        "parameters": [
          {
            "name": "rowField",
            "type": "string",
            "required": false,
            "description": "Field used to create facet rows."
          },
          {
            "name": "columnField",
            "type": "string",
            "required": false,
            "description": "Field used to create facet columns."
          },
          {
            "name": "wrapDirection",
            "type": "string",
            "required": false,
            "description": "Direction to wrap when panels exceed the budget.",
            "default": "row",
            "validation": {
              "enum": [
                "row",
                "column",
                "auto"
              ]
            }
          },
          {
            "name": "maxPanels",
            "type": "number",
            "required": false,
            "description": "Maximum panel count rendered simultaneously.",
            "default": 6,
            "validation": {
              "minimum": 1,
              "maximum": 48
            }
          },
          {
            "name": "sharedChannels",
            "type": "string[]",
            "required": false,
            "description": "Encoding channels that remain synchronized across panels.",
            "default": [
              "x",
              "y",
              "color"
            ]
          },
          {
            "name": "projection",
            "type": "string",
            "required": false,
            "description": "Projection hint consumed by downstream adapters.",
            "default": "cartesian",
            "validation": {
              "enum": [
                "cartesian",
                "polar",
                "radial"
              ]
            }
          }
        ],
        "schema": {
          "viz_layout_type": {
            "type": "string",
            "required": true,
            "description": "Normalized layout identifier.",
            "default": "facet",
            "validation": {
              "enum": [
                "facet"
              ]
            }
          },
          "viz_layout_rows_field": {
            "type": "string",
            "required": false,
            "description": "Data field used to derive facet rows.",
            "defaultFromParameter": "rowField"
          },
          "viz_layout_columns_field": {
            "type": "string",
            "required": false,
            "description": "Data field used to derive facet columns.",
            "defaultFromParameter": "columnField"
          },
          "viz_layout_wrap_direction": {
            "type": "string",
            "required": false,
            "description": "How facets wrap when exceeding panel limits.",
            "defaultFromParameter": "wrapDirection",
            "validation": {
              "enum": [
                "row",
                "column",
                "auto"
              ]
            }
          },
          "viz_layout_max_panels": {
            "type": "number",
            "required": false,
            "description": "Maximum panel count rendered simultaneously.",
            "defaultFromParameter": "maxPanels",
            "validation": {
              "minimum": 1,
              "maximum": 48
            }
          },
          "viz_layout_shared_channels": {
            "type": "string[]",
            "required": false,
            "description": "Channels whose domains remain shared across panels.",
            "defaultFromParameter": "sharedChannels"
          },
          "viz_layout_projection": {
            "type": "string",
            "required": false,
            "description": "Projection metadata forwarded to adapters and docs.",
            "defaultFromParameter": "projection",
            "validation": {
              "enum": [
                "cartesian",
                "polar",
                "radial"
              ]
            }
          },
          "viz_layout_gap": {
            "type": "number",
            "required": false,
            "description": "Gap (px) between panels.",
            "default": 16,
            "validation": {
              "minimum": 0,
              "maximum": 64
            }
          }
        },
        "semantics": {
          "viz_layout_type": {
            "semantic_type": "viz.layout.type",
            "ui_hints": {
              "component": "Badge"
            }
          },
          "viz_layout_rows_field": {
            "semantic_type": "viz.layout.facet.rows",
            "ui_hints": {
              "component": "Code"
            }
          },
          "viz_layout_columns_field": {
            "semantic_type": "viz.layout.facet.columns",
            "ui_hints": {
              "component": "Code"
            }
          },
          "viz_layout_wrap_direction": {
            "semantic_type": "viz.layout.facet.wrap",
            "ui_hints": {
              "component": "Badge"
            }
          },
          "viz_layout_max_panels": {
            "semantic_type": "viz.layout.facet.panels",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "panels"
            }
          },
          "viz_layout_shared_channels": {
            "semantic_type": "viz.layout.shared_channels",
            "ui_hints": {
              "component": "ListSummary"
            }
          },
          "viz_layout_projection": {
            "semantic_type": "viz.layout.projection",
            "ui_hints": {
              "component": "Badge"
            }
          },
          "viz_layout_gap": {
            "semantic_type": "viz.layout.spacing",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "px"
            }
          }
        },
        "tokens": {
          "viz.layout.facet.gap": "var(--cmp-viz-layout-gap)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-16",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems"
          ],
          "maturity": "beta",
          "accessibility": {
            "keyboard": "Facet panels are navigable via arrow keys. Each panel is a tab stop.",
            "screenreader": "Announces facet field name and panel count (e.g., \"Faceted by Region, 6 panels\")."
          },
          "examples": [
            "SalesByRegionFaceted",
            "ChurnByPlanType",
            "TicketVolumeByCategoryAndMonth"
          ],
          "references": [
            "objects/provenance.v1.json#/references/ref-c52ae10b7f25",
            "Sprint 23 plan"
          ]
        },
        "objects": [],
        "source": "traits/viz/layout-facet.trait.yaml"
      },
      "LayoutLayer": {
        "name": "LayoutLayer",
        "version": "0.2.0",
        "description": "Governs sequencing, blending, and shared channel behavior for layered mark compositions.",
        "category": "viz.layout",
        "tags": [
          "viz",
          "layout",
          "layer",
          "composition"
        ],
        "contexts": [],
        "viewExtensions": [],
        "parameters": [
          {
            "name": "blendMode",
            "type": "string",
            "required": false,
            "description": "Blend/composite mode applied across stacked marks.",
            "default": "normal",
            "validation": {
              "enum": [
                "normal",
                "multiply",
                "screen",
                "overlay"
              ]
            }
          },
          {
            "name": "syncInteractions",
            "type": "boolean",
            "required": false,
            "description": "Whether interaction predicates propagate across all layers.",
            "default": true
          },
          {
            "name": "sharedChannels",
            "type": "string[]",
            "required": false,
            "description": "Channels whose scales remain synchronized across layers.",
            "default": [
              "x",
              "y",
              "color"
            ]
          },
          {
            "name": "orderHint",
            "type": "string[]",
            "required": false,
            "description": "Optional list describing explicit bottom→top layer ordering. Entries name layers by mark options.id when set (preferred — repeated same-trait marks need distinct ids to be addressable), else by mark trait."
          },
          {
            "name": "projection",
            "type": "string",
            "required": false,
            "description": "Projection hint for adapters when layering across spaces.",
            "default": "cartesian",
            "validation": {
              "enum": [
                "cartesian",
                "polar",
                "radial"
              ]
            }
          }
        ],
        "schema": {
          "viz_layout_type": {
            "type": "string",
            "required": true,
            "description": "Normalized layout identifier.",
            "default": "layer",
            "validation": {
              "enum": [
                "layer"
              ]
            }
          },
          "viz_layout_blend_mode": {
            "type": "string",
            "required": false,
            "description": "Blend/composite mode applied to layered marks.",
            "defaultFromParameter": "blendMode",
            "validation": {
              "enum": [
                "normal",
                "multiply",
                "screen",
                "overlay"
              ]
            }
          },
          "viz_layout_sync_interactions": {
            "type": "boolean",
            "required": false,
            "description": "Whether interaction predicates are shared across layers.",
            "defaultFromParameter": "syncInteractions"
          },
          "viz_layout_shared_channels": {
            "type": "string[]",
            "required": false,
            "description": "Channels that share a domain across layered marks.",
            "defaultFromParameter": "sharedChannels"
          },
          "viz_layout_order_hint": {
            "type": "string[]",
            "required": false,
            "description": "Optional ordered list describing layer precedence.",
            "defaultFromParameter": "orderHint"
          },
          "viz_layout_projection": {
            "type": "string",
            "required": false,
            "description": "Projection metadata forwarded to adapters and docs.",
            "defaultFromParameter": "projection",
            "validation": {
              "enum": [
                "cartesian",
                "polar",
                "radial"
              ]
            }
          }
        },
        "semantics": {
          "viz_layout_type": {
            "semantic_type": "viz.layout.type",
            "ui_hints": {
              "component": "Badge"
            }
          },
          "viz_layout_blend_mode": {
            "semantic_type": "viz.layout.layer.blend",
            "ui_hints": {
              "component": "Badge"
            }
          },
          "viz_layout_sync_interactions": {
            "semantic_type": "viz.layout.layer.sync_interactions",
            "ui_hints": {
              "component": "BooleanPill"
            }
          },
          "viz_layout_shared_channels": {
            "semantic_type": "viz.layout.shared_channels",
            "ui_hints": {
              "component": "ListSummary"
            }
          },
          "viz_layout_order_hint": {
            "semantic_type": "viz.layout.layer.order",
            "ui_hints": {
              "component": "ListSummary"
            }
          },
          "viz_layout_projection": {
            "semantic_type": "viz.layout.projection",
            "ui_hints": {
              "component": "Badge"
            }
          }
        },
        "tokens": {
          "viz.layout.layer.blend": "var(--cmp-viz-layer-blend)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-16",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems"
          ],
          "maturity": "beta",
          "accessibility": {
            "keyboard": "Layer order is keyboard-traversable. Focus moves through layers bottom to top.",
            "screenreader": "Announces layer count and blend mode (e.g., \"Layered visualization, 3 layers, normal blend\")."
          },
          "examples": [
            "LineWithConfidenceBand",
            "BarWithTrendOverlay",
            "ScatterWithRegressionLine"
          ],
          "references": [
            "objects/provenance.v1.json#/references/ref-c52ae10b7f25"
          ]
        },
        "objects": [],
        "source": "traits/viz/layout-layer.trait.yaml"
      },
      "MarkArea": {
        "name": "MarkArea",
        "version": "0.2.0",
        "description": "Canonical area mark for cumulative totals and ranges. Fills the region\nbetween the series baseline and value curve with configurable opacity and\ninterpolation.",
        "category": "viz.mark",
        "tags": [
          "viz",
          "mark",
          "area",
          "band"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "VizAreaPreview",
            "context": "detail",
            "position": "top",
            "priority": 55,
            "props": {
              "curveField": "viz_area_curve",
              "opacityField": "viz_area_opacity",
              "svgParameter": "previewSvg",
              "baselineField": "viz_area_baseline"
            }
          },
          {
            "component": "VizAreaControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "curveField": "viz_area_curve",
              "opacityField": "viz_area_opacity",
              "baselineField": "viz_area_baseline",
              "tensionField": "viz_area_tension"
            }
          },
          {
            "component": "VizRoleBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "labelField": "viz_mark_role"
            }
          }
        ],
        "parameters": [
          {
            "name": "chart",
            "type": "object",
            "required": false,
            "description": "Optional read-only chart declaration binding existing domain fields; projects into supported detail and dashboard views."
          },
          {
            "name": "title",
            "type": "string",
            "required": false,
            "description": "Title for the bound chart and its accessible figure.",
            "default": "Payment amounts"
          },
          {
            "name": "description",
            "type": "string",
            "required": false,
            "description": "Description of the bound chart measurements and units.",
            "default": "Values recorded for this record."
          },
          {
            "name": "previewSvg",
            "type": "string",
            "required": false,
            "description": "Static SVG returned by viz.render for the authored sample."
          },
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "curve",
            "type": "string",
            "required": false,
            "description": "Curve interpolation strategy applied between samples.",
            "default": "linear",
            "validation": {
              "enum": [
                "linear",
                "monotone",
                "step"
              ]
            }
          },
          {
            "name": "opacity",
            "type": "number",
            "required": false,
            "description": "Fill opacity used for the area band.",
            "default": 0.65,
            "validation": {
              "minimum": 0.2,
              "maximum": 1
            }
          },
          {
            "name": "baseline",
            "type": "string",
            "required": false,
            "description": "Baseline reference for filling the region (zero, min, or custom).",
            "default": "zero",
            "validation": {
              "enum": [
                "zero",
                "min"
              ]
            }
          },
          {
            "name": "tension",
            "type": "number",
            "required": false,
            "description": "Curve tension applied when using monotone interpolation.",
            "default": 0.3,
            "validation": {
              "minimum": 0,
              "maximum": 1
            }
          }
        ],
        "schema": {
          "viz_mark_type": {
            "type": "string",
            "required": true,
            "description": "Normalized mark identifier consumed by renderer adapters.",
            "default": "area",
            "validation": {
              "enum": [
                "area"
              ]
            }
          },
          "viz_area_curve": {
            "type": "string",
            "required": false,
            "description": "Interpolation strategy applied between samples.",
            "defaultFromParameter": "curve",
            "validation": {
              "enum": [
                "linear",
                "monotone",
                "step"
              ]
            }
          },
          "viz_area_opacity": {
            "type": "number",
            "required": false,
            "description": "Fill opacity used for the area band.",
            "defaultFromParameter": "opacity",
            "validation": {
              "minimum": 0.2,
              "maximum": 1
            }
          },
          "viz_area_baseline": {
            "type": "string",
            "required": false,
            "description": "Baseline reference for filling the region.",
            "defaultFromParameter": "baseline",
            "validation": {
              "enum": [
                "zero",
                "min"
              ]
            }
          },
          "viz_area_tension": {
            "type": "number",
            "required": false,
            "description": "Curve tension applied when smoothing.",
            "defaultFromParameter": "tension",
            "validation": {
              "minimum": 0,
              "maximum": 1
            }
          },
          "viz_mark_role": {
            "type": "string",
            "required": true,
            "description": "Semantic role for heuristics and docs.",
            "default": "band"
          },
          "viz_mark_a11y_label": {
            "type": "string",
            "required": true,
            "description": "Accessible description fragment for describing area marks.",
            "default": "Area mark representing cumulative or range-based values."
          }
        },
        "semantics": {
          "viz_mark_type": {
            "semantic_type": "viz.mark.type",
            "token_mapping": "tokenMap(viz.mark.type)",
            "ui_hints": {
              "component": "VizMarkSummary"
            }
          },
          "viz_area_curve": {
            "semantic_type": "viz.mark.curve",
            "token_mapping": "tokenMap(viz.mark.curve)",
            "ui_hints": {
              "component": "VizCurveHint"
            }
          },
          "viz_area_opacity": {
            "semantic_type": "viz.mark.opacity",
            "token_mapping": "tokenMap(viz.mark.opacity)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "opacity"
            }
          },
          "viz_area_baseline": {
            "semantic_type": "viz.mark.baseline",
            "token_mapping": "tokenMap(viz.mark.baseline)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_mark_a11y_label": {
            "semantic_type": "a11y.description",
            "token_mapping": "tokenMap(a11y.chart.description)",
            "ui_hints": {
              "component": "ScreenReaderHint"
            }
          }
        },
        "tokens": {
          "viz.mark.area.fill.default": "var(--cmp-viz-mark-area-fill)",
          "viz.mark.area.opacity.default": "var(--cmp-viz-mark-area-opacity)",
          "viz.mark.area.baseline.stroke": "var(--cmp-viz-axis-base)"
        },
        "dependencies": [
          "EncodingPositionX",
          "EncodingPositionY"
        ],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "design@oods.systems"
          ],
          "maturity": "alpha",
          "conflicts_with": [
            "MarkBar",
            "MarkLine",
            "MarkPoint"
          ],
          "accessibility": {
            "rule_reference": "A11Y-R-06",
            "notes": "Convey baseline reference in descriptive text output."
          },
          "regionsUsed": [
            "detail",
            "form",
            "list"
          ],
          "examples": [
            "ForecastRange",
            "BurnDownVariance"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/mark-area.trait.yaml"
      },
      "MarkBar": {
        "name": "MarkBar",
        "version": "0.2.0",
        "description": "Canonical rectangular mark for magnitude comparisons. Supports stacked\nor grouped categories and enforces RDS.7 accessibility requirements for\nredundant encodings.",
        "category": "viz.mark",
        "tags": [
          "viz",
          "mark",
          "bar",
          "comparison"
        ],
        "contexts": [
          "dashboard",
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "VizMarkPreview",
            "context": "detail",
            "position": "top",
            "priority": 60,
            "props": {
              "svgParameter": "previewSvg",
              "typeField": "viz_mark_type",
              "orientationField": "viz_mark_orientation",
              "stackingField": "viz_mark_stacking"
            }
          },
          {
            "component": "VizMarkPreview",
            "context": "dashboard",
            "position": "top",
            "priority": 60,
            "props": {
              "svgParameter": "previewSvg",
              "typeField": "viz_mark_type",
              "orientationField": "viz_mark_orientation",
              "stackingField": "viz_mark_stacking"
            }
          },
          {
            "component": "VizMarkControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "orientationField": "viz_mark_orientation",
              "paddingField": "viz_mark_band_padding",
              "stackingField": "viz_mark_stacking",
              "cornerRadiusField": "viz_mark_corner_radius"
            }
          },
          {
            "component": "VizRoleBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "labelField": "viz_mark_role"
            }
          }
        ],
        "parameters": [
          {
            "name": "chart",
            "type": "object",
            "required": false,
            "description": "Optional read-only chart declaration binding existing domain fields; projects into supported detail and dashboard views."
          },
          {
            "name": "title",
            "type": "string",
            "required": false,
            "description": "Title for the bound chart and its accessible figure."
          },
          {
            "name": "description",
            "type": "string",
            "required": false,
            "description": "Description of the bound chart measurements and units."
          },
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "previewSvg",
            "type": "string",
            "required": false,
            "description": "Static SVG returned by viz.render for the authored sample; omitted until a chart is rendered."
          },
          {
            "name": "orientation",
            "type": "string",
            "required": true,
            "description": "Axis orientation used for laying out bar rectangles.",
            "default": "vertical",
            "validation": {
              "enum": [
                "vertical",
                "horizontal"
              ]
            }
          },
          {
            "name": "bandPadding",
            "type": "number",
            "required": false,
            "description": "Fractional padding between category bands (0-0.5).",
            "default": 0.1,
            "validation": {
              "minimum": 0,
              "maximum": 0.5
            }
          },
          {
            "name": "cornerRadius",
            "type": "number",
            "required": false,
            "description": "Pixel radius applied to bar corners.",
            "default": 2,
            "validation": {
              "minimum": 0,
              "maximum": 12
            }
          },
          {
            "name": "stacking",
            "type": "string",
            "required": false,
            "description": "Aggregation strategy when multiple series share the mark.",
            "default": "auto",
            "validation": {
              "enum": [
                "auto",
                "normalize",
                "none"
              ]
            }
          }
        ],
        "schema": {
          "viz_mark_type": {
            "type": "string",
            "required": true,
            "description": "Normalized mark identifier consumed by renderer adapters.",
            "default": "bar",
            "validation": {
              "enum": [
                "bar"
              ]
            }
          },
          "viz_mark_orientation": {
            "type": "string",
            "required": true,
            "description": "Orientation flag for aligning axes and fallbacks.",
            "defaultFromParameter": "orientation",
            "validation": {
              "enum": [
                "vertical",
                "horizontal"
              ]
            }
          },
          "viz_mark_band_padding": {
            "type": "number",
            "required": false,
            "description": "Fractional padding between bars within a category.",
            "defaultFromParameter": "bandPadding",
            "validation": {
              "minimum": 0,
              "maximum": 0.5
            }
          },
          "viz_mark_corner_radius": {
            "type": "number",
            "required": false,
            "description": "Corner radius applied to rendered bars.",
            "defaultFromParameter": "cornerRadius",
            "validation": {
              "minimum": 0,
              "maximum": 12
            }
          },
          "viz_mark_stacking": {
            "type": "string",
            "required": false,
            "description": "Stacking semantics applied to grouped series.",
            "defaultFromParameter": "stacking",
            "validation": {
              "enum": [
                "auto",
                "normalize",
                "none"
              ]
            }
          },
          "viz_mark_role": {
            "type": "string",
            "required": true,
            "description": "Semantic role used by heuristics, docs, and filtering.",
            "default": "comparison"
          },
          "viz_mark_a11y_label": {
            "type": "string",
            "required": true,
            "description": "Accessible description fragment for assistive tech fallbacks.",
            "default": "Bar mark showing magnitude per category."
          }
        },
        "semantics": {
          "viz_mark_type": {
            "semantic_type": "viz.mark.type",
            "token_mapping": "tokenMap(viz.mark.type)",
            "ui_hints": {
              "component": "VizMarkSummary"
            }
          },
          "viz_mark_orientation": {
            "semantic_type": "viz.mark.orientation",
            "token_mapping": "tokenMap(viz.mark.orientation)",
            "ui_hints": {
              "component": "VizOrientationBadge"
            }
          },
          "viz_mark_band_padding": {
            "semantic_type": "viz.mark.spacing",
            "token_mapping": "tokenMap(viz.mark.spacing)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "fraction"
            }
          },
          "viz_mark_corner_radius": {
            "semantic_type": "viz.mark.corner_radius",
            "token_mapping": "tokenMap(viz.mark.corner_radius)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "px"
            }
          },
          "viz_mark_stacking": {
            "semantic_type": "viz.mark.stacking",
            "token_mapping": "tokenMap(viz.mark.stacking)",
            "ui_hints": {
              "component": "VizStackingHint"
            }
          },
          "viz_mark_a11y_label": {
            "semantic_type": "a11y.description",
            "token_mapping": "tokenMap(a11y.chart.description)",
            "ui_hints": {
              "component": "ScreenReaderHint"
            }
          }
        },
        "tokens": {
          "viz.mark.bar.fill.default": "var(--cmp-viz-mark-bar-fill)",
          "viz.mark.bar.stroke.default": "var(--cmp-viz-mark-bar-stroke)",
          "viz.mark.bar.spacing": "var(--cmp-viz-mark-spacing)"
        },
        "dependencies": [
          "EncodingPositionX",
          "EncodingPositionY"
        ],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "design@oods.systems"
          ],
          "maturity": "alpha",
          "conflicts_with": [
            "MarkLine",
            "MarkPoint",
            "MarkArea"
          ],
          "accessibility": {
            "rule_reference": "A11Y-R-04",
            "notes": "Requires redundant text/table fallback in paired specs."
          },
          "regionsUsed": [
            "detail",
            "dashboard",
            "form",
            "list"
          ],
          "examples": [
            "RevenueByRegion",
            "TicketVolumeByQueue"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [
          "Invoice",
          "Subscription"
        ],
        "source": "traits/viz/mark-bar.trait.yaml"
      },
      "MarkGraph": {
        "name": "MarkGraph",
        "version": "0.1.0",
        "description": "Read-only force graph over a declared neighborhood edge array, rendered by public viz.render.",
        "category": "viz.mark",
        "tags": [
          "viz",
          "mark",
          "graph",
          "relationship"
        ],
        "contexts": [
          "detail"
        ],
        "viewExtensions": [
          {
            "component": "VizGraphPreview",
            "context": "detail",
            "position": "top",
            "priority": 60,
            "props": {
              "svgParameter": "previewSvg"
            }
          }
        ],
        "parameters": [
          {
            "name": "chart",
            "type": "object",
            "required": false,
            "description": "Declared edge-array chart source for the host object's neighborhood."
          },
          {
            "name": "title",
            "type": "string",
            "required": false,
            "description": "Title for the chart and its accessible figure."
          },
          {
            "name": "description",
            "type": "string",
            "required": false,
            "description": "Accessible description including the provenance of example edges."
          },
          {
            "name": "previewSvg",
            "type": "string",
            "required": false,
            "description": "Static SVG returned by public viz.render."
          }
        ],
        "schema": {
          "viz_mark_type": {
            "type": "string",
            "required": true,
            "default": "graph",
            "description": "Normalized graph mark identifier.",
            "validation": {
              "enum": [
                "graph"
              ]
            }
          }
        },
        "semantics": {},
        "tokens": {},
        "dependencies": [],
        "metadata": {
          "created": "2026-09-14",
          "updated": "2026-09-14",
          "owners": [
            "viz@oods.systems"
          ],
          "maturity": "alpha",
          "regionsUsed": [
            "detail"
          ],
          "accessibility": {
            "notes": "The wrapper names the static graph; node identifiers and the description remain available without color or interaction."
          }
        },
        "objects": [
          "Relationship"
        ],
        "source": "traits/viz/mark-graph.trait.yaml"
      },
      "MarkLine": {
        "name": "MarkLine",
        "version": "0.2.0",
        "description": "Canonical line mark for trends, rates, and progressions. Encodes values as\nconnected segments with configurable curve smoothing and join policies.",
        "category": "viz.mark",
        "tags": [
          "viz",
          "mark",
          "line",
          "trend"
        ],
        "contexts": [
          "dashboard",
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "VizLinePreview",
            "context": "detail",
            "position": "top",
            "priority": 60,
            "props": {
              "svgParameter": "previewSvg",
              "curveField": "viz_line_curve",
              "strokeWidthField": "viz_line_stroke_width",
              "markersField": "viz_line_markers"
            }
          },
          {
            "component": "VizLinePreview",
            "context": "dashboard",
            "position": "top",
            "priority": 60,
            "props": {
              "svgParameter": "previewSvg",
              "curveField": "viz_line_curve",
              "strokeWidthField": "viz_line_stroke_width",
              "markersField": "viz_line_markers"
            }
          },
          {
            "component": "VizLineControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "curveField": "viz_line_curve",
              "strokeField": "viz_line_stroke_width",
              "joinField": "viz_line_join",
              "markersField": "viz_line_markers"
            }
          },
          {
            "component": "VizRoleBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "labelField": "viz_mark_role"
            }
          }
        ],
        "parameters": [
          {
            "name": "chart",
            "type": "object",
            "required": false,
            "description": "Optional read-only chart declaration binding existing domain fields; projects into supported detail and dashboard views."
          },
          {
            "name": "title",
            "type": "string",
            "required": false,
            "description": "Title for the bound chart and its accessible figure."
          },
          {
            "name": "description",
            "type": "string",
            "required": false,
            "description": "Description of the bound chart measurements and units."
          },
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "previewSvg",
            "type": "string",
            "required": false,
            "description": "Static SVG returned by viz.render for the authored sample; omitted until a chart is rendered."
          },
          {
            "name": "curve",
            "type": "string",
            "required": false,
            "description": "Curve interpolation strategy applied between data points.",
            "default": "linear",
            "validation": {
              "enum": [
                "linear",
                "monotone",
                "step"
              ]
            }
          },
          {
            "name": "strokeWidth",
            "type": "number",
            "required": false,
            "description": "Stroke width in device-independent pixels.",
            "default": 2,
            "validation": {
              "minimum": 1,
              "maximum": 8
            }
          },
          {
            "name": "join",
            "type": "string",
            "required": false,
            "description": "Join style applied when segments meet.",
            "default": "round",
            "validation": {
              "enum": [
                "miter",
                "round",
                "bevel"
              ]
            }
          },
          {
            "name": "enableMarkers",
            "type": "boolean",
            "required": false,
            "description": "Adds optional point markers on line vertices.",
            "default": false
          }
        ],
        "schema": {
          "viz_mark_type": {
            "type": "string",
            "required": true,
            "description": "Normalized mark identifier consumed by renderer adapters.",
            "default": "line",
            "validation": {
              "enum": [
                "line"
              ]
            }
          },
          "viz_line_curve": {
            "type": "string",
            "required": false,
            "description": "Curve interpolation strategy derived from parameters.",
            "defaultFromParameter": "curve",
            "validation": {
              "enum": [
                "linear",
                "monotone",
                "step"
              ]
            }
          },
          "viz_line_stroke_width": {
            "type": "number",
            "required": false,
            "description": "Stroke width in pixels.",
            "defaultFromParameter": "strokeWidth",
            "validation": {
              "minimum": 1,
              "maximum": 8
            }
          },
          "viz_line_join": {
            "type": "string",
            "required": false,
            "description": "Join style used for connecting segments.",
            "defaultFromParameter": "join",
            "validation": {
              "enum": [
                "miter",
                "round",
                "bevel"
              ]
            }
          },
          "viz_line_markers": {
            "type": "boolean",
            "required": false,
            "description": "Indicates whether point markers render along the series.",
            "defaultFromParameter": "enableMarkers"
          },
          "viz_mark_role": {
            "type": "string",
            "required": true,
            "description": "Semantic role used for heuristics and docs.",
            "default": "trend"
          },
          "viz_mark_a11y_label": {
            "type": "string",
            "required": true,
            "description": "Accessible description fragment for describing the line mark.",
            "default": "Line mark showing change over time or ordered categories."
          }
        },
        "semantics": {
          "viz_mark_type": {
            "semantic_type": "viz.mark.type",
            "token_mapping": "tokenMap(viz.mark.type)",
            "ui_hints": {
              "component": "VizMarkSummary"
            }
          },
          "viz_line_curve": {
            "semantic_type": "viz.mark.curve",
            "token_mapping": "tokenMap(viz.mark.curve)",
            "ui_hints": {
              "component": "VizCurveHint"
            }
          },
          "viz_line_stroke_width": {
            "semantic_type": "viz.mark.stroke_width",
            "token_mapping": "tokenMap(viz.mark.stroke_width)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "px"
            }
          },
          "viz_line_join": {
            "semantic_type": "viz.mark.join",
            "token_mapping": "tokenMap(viz.mark.join)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_line_markers": {
            "semantic_type": "viz.mark.markers",
            "token_mapping": "tokenMap(viz.mark.marker)",
            "ui_hints": {
              "component": "BooleanBadge"
            }
          },
          "viz_mark_a11y_label": {
            "semantic_type": "a11y.description",
            "token_mapping": "tokenMap(a11y.chart.description)",
            "ui_hints": {
              "component": "ScreenReaderHint"
            }
          }
        },
        "tokens": {
          "viz.mark.line.stroke.default": "var(--cmp-viz-mark-line-stroke)",
          "viz.mark.line.stroke.highlight": "var(--cmp-viz-mark-line-highlight)",
          "viz.mark.line.marker.fill": "var(--cmp-viz-mark-point-fill)"
        },
        "dependencies": [
          "EncodingPositionX",
          "EncodingPositionY"
        ],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "design@oods.systems"
          ],
          "maturity": "alpha",
          "conflicts_with": [
            "MarkBar",
            "MarkPoint",
            "MarkArea"
          ],
          "accessibility": {
            "rule_reference": "A11Y-R-05",
            "notes": "Provide textual summary for trend direction and extrema."
          },
          "regionsUsed": [
            "detail",
            "dashboard",
            "form",
            "list"
          ],
          "examples": [
            "ActiveUsersTrend",
            "ConversionRateTimeline"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [
          "Usage"
        ],
        "source": "traits/viz/mark-line.trait.yaml"
      },
      "MarkPoint": {
        "name": "MarkPoint",
        "version": "0.2.0",
        "description": "Canonical point mark for scatterplots and overlays. Encodes each datum as a\ndiscrete glyph with configurable shape, size, and fill semantics.",
        "category": "viz.mark",
        "tags": [
          "viz",
          "mark",
          "point",
          "distribution"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "VizPointPreview",
            "context": "detail",
            "position": "top",
            "priority": 55,
            "props": {
              "svgParameter": "previewSvg",
              "shapeField": "viz_point_shape",
              "sizeField": "viz_point_size",
              "fillField": "viz_point_fill"
            }
          },
          {
            "component": "VizPointControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "shapeField": "viz_point_shape",
              "sizeField": "viz_point_size",
              "opacityField": "viz_point_opacity",
              "strokeField": "viz_point_stroke_width"
            }
          },
          {
            "component": "VizRoleBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "labelField": "viz_mark_role"
            }
          }
        ],
        "parameters": [
          {
            "name": "chart",
            "type": "object",
            "required": false,
            "description": "Optional read-only chart declaration binding existing domain fields; projects into supported detail and dashboard views."
          },
          {
            "name": "title",
            "type": "string",
            "required": false,
            "description": "Title for the bound chart and its accessible figure."
          },
          {
            "name": "description",
            "type": "string",
            "required": false,
            "description": "Description of the bound chart measurements and units."
          },
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "previewSvg",
            "type": "string",
            "required": false,
            "description": "Static SVG returned by viz.render for the authored sample; omitted until a chart is rendered."
          },
          {
            "name": "shape",
            "type": "string",
            "required": false,
            "description": "Glyph shape rendered for each data point.",
            "default": "circle",
            "validation": {
              "enum": [
                "circle",
                "square",
                "diamond",
                "triangle"
              ]
            }
          },
          {
            "name": "size",
            "type": "number",
            "required": false,
            "description": "Default glyph area in square pixels.",
            "default": 48,
            "validation": {
              "minimum": 4,
              "maximum": 196
            }
          },
          {
            "name": "fill",
            "type": "string",
            "required": false,
            "description": "Fill strategy for glyph interior.",
            "default": "solid",
            "validation": {
              "enum": [
                "solid",
                "hollow"
              ]
            }
          },
          {
            "name": "strokeWidth",
            "type": "number",
            "required": false,
            "description": "Outline stroke width for hollow glyphs.",
            "default": 1,
            "validation": {
              "minimum": 0,
              "maximum": 6
            }
          },
          {
            "name": "opacity",
            "type": "number",
            "required": false,
            "description": "Default opacity applied to each point for overplotting.",
            "default": 0.85,
            "validation": {
              "minimum": 0.1,
              "maximum": 1
            }
          }
        ],
        "schema": {
          "viz_mark_type": {
            "type": "string",
            "required": true,
            "description": "Normalized mark identifier consumed by renderer adapters.",
            "default": "point",
            "validation": {
              "enum": [
                "point"
              ]
            }
          },
          "viz_point_shape": {
            "type": "string",
            "required": false,
            "description": "Glyph shape applied to all rendered points by default.",
            "defaultFromParameter": "shape",
            "validation": {
              "enum": [
                "circle",
                "square",
                "diamond",
                "triangle"
              ]
            }
          },
          "viz_point_size": {
            "type": "number",
            "required": false,
            "description": "Default glyph area in square pixels.",
            "defaultFromParameter": "size",
            "validation": {
              "minimum": 4,
              "maximum": 196
            }
          },
          "viz_point_fill": {
            "type": "string",
            "required": false,
            "description": "Fill strategy for glyph interior.",
            "defaultFromParameter": "fill",
            "validation": {
              "enum": [
                "solid",
                "hollow"
              ]
            }
          },
          "viz_point_stroke_width": {
            "type": "number",
            "required": false,
            "description": "Outline stroke width for hollow glyphs.",
            "defaultFromParameter": "strokeWidth",
            "validation": {
              "minimum": 0,
              "maximum": 6
            }
          },
          "viz_point_opacity": {
            "type": "number",
            "required": false,
            "description": "Default opacity used for overplotting mitigation.",
            "defaultFromParameter": "opacity",
            "validation": {
              "minimum": 0.1,
              "maximum": 1
            }
          },
          "viz_mark_role": {
            "type": "string",
            "required": true,
            "description": "Semantic role for heuristics and docs.",
            "default": "distribution"
          },
          "viz_mark_a11y_label": {
            "type": "string",
            "required": true,
            "description": "Accessible description fragment for describing point marks.",
            "default": "Point mark representing discrete values or observations."
          }
        },
        "semantics": {
          "viz_mark_type": {
            "semantic_type": "viz.mark.type",
            "token_mapping": "tokenMap(viz.mark.type)",
            "ui_hints": {
              "component": "VizMarkSummary"
            }
          },
          "viz_point_shape": {
            "semantic_type": "viz.mark.shape",
            "token_mapping": "tokenMap(viz.mark.shape)",
            "ui_hints": {
              "component": "VizShapeHint"
            }
          },
          "viz_point_size": {
            "semantic_type": "viz.mark.size",
            "token_mapping": "tokenMap(viz.mark.size)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "px^2"
            }
          },
          "viz_point_fill": {
            "semantic_type": "viz.mark.fill",
            "token_mapping": "tokenMap(viz.mark.fill)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_point_opacity": {
            "semantic_type": "viz.mark.opacity",
            "token_mapping": "tokenMap(viz.mark.opacity)",
            "ui_hints": {
              "component": "NumericPreview",
              "unit": "opacity"
            }
          },
          "viz_mark_a11y_label": {
            "semantic_type": "a11y.description",
            "token_mapping": "tokenMap(a11y.chart.description)",
            "ui_hints": {
              "component": "ScreenReaderHint"
            }
          }
        },
        "tokens": {
          "viz.mark.point.fill.default": "var(--cmp-viz-mark-point-fill)",
          "viz.mark.point.stroke.default": "var(--cmp-viz-mark-point-stroke)",
          "viz.mark.point.opacity.default": "var(--cmp-viz-mark-point-opacity)"
        },
        "dependencies": [
          "EncodingPositionX",
          "EncodingPositionY"
        ],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "design@oods.systems"
          ],
          "maturity": "alpha",
          "conflicts_with": [
            "MarkBar",
            "MarkLine",
            "MarkArea"
          ],
          "accessibility": {
            "rule_reference": "A11Y-R-01",
            "notes": "Provide redundant encoding (color, shape, or texture) per RDV.4."
          },
          "regionsUsed": [
            "detail",
            "form",
            "list"
          ],
          "examples": [
            "ProfitVsRevenue",
            "SLAHeatScatter"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/mark-point.trait.yaml"
      },
      "MarkRect": {
        "name": "MarkRect",
        "version": "0.1.0",
        "description": "Heatmap authoring over the existing MarkRect renderer",
        "category": "viz.mark",
        "tags": [
          "viz",
          "authoring"
        ],
        "contexts": [
          "detail",
          "form"
        ],
        "viewExtensions": [
          {
            "component": "VizHeatmapControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent"
            }
          },
          {
            "component": "VizHeatmapPreview",
            "context": "detail",
            "position": "top",
            "priority": null,
            "props": {
              "svgParameter": "previewSvg"
            }
          }
        ],
        "parameters": [
          {
            "name": "chart",
            "type": "object",
            "required": false,
            "description": "Optional read-only chart declaration binding existing domain fields; projects into supported detail and dashboard views."
          },
          {
            "name": "title",
            "type": "string",
            "required": false,
            "description": "Title for the bound chart and its accessible figure."
          },
          {
            "name": "description",
            "type": "string",
            "required": false,
            "description": "Description of the bound chart measurements and units."
          },
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment; data rows are supplied by the consumer."
          },
          {
            "name": "previewSvg",
            "type": "string",
            "required": false,
            "description": "Static SVG returned by viz.render for the authored sample."
          }
        ],
        "schema": {},
        "semantics": {},
        "tokens": {},
        "dependencies": [],
        "metadata": {
          "regionsUsed": [
            "form",
            "detail"
          ]
        },
        "objects": [],
        "source": "traits/viz/mark-rect.trait.yaml"
      },
      "Ownerable": {
        "name": "Ownerable",
        "version": "1.0.0",
        "description": "Adds ownership metadata linking entities to their governing account or principal with transfer auditing.",
        "category": "structural",
        "tags": [
          "ownership",
          "governance",
          "relationships",
          "access"
        ],
        "contexts": [
          "card",
          "detail",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "OwnershipSummary",
            "context": "detail",
            "position": "top",
            "priority": null,
            "props": {
              "ownerIdField": "owner_id",
              "ownerTypeField": "owner_type",
              "roleField": "ownership_role",
              "transferredAtField": "ownership_transferred_at",
              "allowTransferParameter": "allowTransfer"
            }
          },
          {
            "component": "OwnerBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "ownerIdField": "owner_id",
              "ownerTypeField": "owner_type"
            }
          },
          {
            "component": "OwnershipMeta",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "ownerIdField": "owner_id",
              "ownerTypeField": "owner_type",
              "roleField": "ownership_role"
            }
          }
        ],
        "parameters": [
          {
            "name": "ownerTypes",
            "type": "string[]",
            "required": true,
            "description": "Allow list of principals permitted to own the entity.",
            "default": [
              "organization",
              "team",
              "user"
            ]
          },
          {
            "name": "primaryOwnerType",
            "type": "string",
            "required": false,
            "description": "Default owner type applied when authoring new records.",
            "default": "organization",
            "validation": {
              "enumFromParameter": "ownerTypes"
            }
          },
          {
            "name": "allowTransfer",
            "type": "boolean",
            "required": false,
            "description": "Whether ownership may be reassigned after initial creation.",
            "default": true
          }
        ],
        "schema": {
          "owner_id": {
            "type": "string",
            "required": true,
            "description": "Identifier of the owning principal scoped by owner_type."
          },
          "owner_type": {
            "type": "string",
            "required": true,
            "description": "Categorical owner type sourced from the ownerTypes parameter.",
            "validation": {
              "enumFromParameter": "ownerTypes"
            }
          },
          "ownership_role": {
            "type": "string",
            "required": false,
            "description": "Optional role name describing how the owner governs the entity.",
            "validation": {
              "maxLength": 80
            }
          },
          "ownership_transferred_at": {
            "type": "datetime",
            "required": false,
            "description": "Timestamp recording when ownership was last transferred."
          }
        },
        "semantics": {
          "owner_id": {
            "semantic_type": "ownership.owner.id",
            "token_mapping": "tokenMap(ownership.owner.id)",
            "ui_hints": {
              "component": "OwnerReference",
              "ownerTypeField": "owner_type"
            }
          },
          "owner_type": {
            "semantic_type": "ownership.owner.type",
            "token_mapping": "tokenMap(ownership.owner.type)",
            "ui_hints": {
              "component": "OwnerTypeBadge",
              "parameterSource": "ownerTypes"
            }
          },
          "ownership_role": {
            "semantic_type": "ownership.owner.role",
            "token_mapping": "tokenMap(ownership.owner.role)",
            "ui_hints": {
              "component": "OwnerRolePill"
            }
          },
          "ownership_transferred_at": {
            "semantic_type": "ownership.owner.transferred_at",
            "token_mapping": "tokenMap(ownership.owner.timestamp)",
            "ui_hints": {
              "component": "TimelineTimestamp"
            }
          }
        },
        "tokens": {
          "ownership.owner.badge.bg": "var(--surface-subtle)",
          "ownership.owner.badge.text": "var(--text-default)",
          "ownership.owner.role.text": "var(--text-muted)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-10-16",
          "owners": [
            "governance@oods.systems",
            "platform@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "n/a",
            "screenreader": "Announces owning principal, type, and transfer state."
          },
          "regionsUsed": [
            "detail",
            "list",
            "card"
          ],
          "examples": [
            "Project",
            "Workspace"
          ],
          "references": [
            "Trait Engine Spec v0.1 §2"
          ]
        },
        "objects": [
          "Organization",
          "Plan",
          "Relationship"
        ],
        "source": "traits/structural/Ownerable.trait.yaml"
      },
      "Pageable": {
        "name": "Pageable",
        "version": "1.0.0",
        "description": "Adds pagination controls to list and collection views. Pageable injects a pagination bar\ninto the footer region, wires page state to the data layer, and provides semantic token\nmappings for consistent pagination UI styling across brands.\n\nThe trait supports configurable page sizes, total item counts for page calculation,\nand both simple (prev/next) and full (goto page) navigation modes. Page state is managed\nvia the page and pageSize props, which the consuming layout binds to data offset/limit\nparameters or API pagination cursors.",
        "category": "behavioral",
        "tags": [
          "pagination",
          "list-behavior",
          "navigation",
          "data-loading"
        ],
        "contexts": [
          "list"
        ],
        "viewExtensions": [
          {
            "component": "PaginationBar",
            "context": "list",
            "position": "footer",
            "priority": 10,
            "props": {
              "pageField": "page",
              "pageSizeField": "pageSize",
              "totalItemsField": "totalItems",
              "totalPagesField": "totalPages",
              "pageSizeOptionsParameter": "pageSizeOptions",
              "showPageSizeSelectorParameter": "showPageSizeSelector",
              "showGotoPageParameter": "showGotoPage",
              "showItemRangeParameter": "showItemRange"
            }
          }
        ],
        "parameters": [
          {
            "name": "defaultPageSize",
            "type": "number",
            "required": false,
            "description": "Default number of items per page.",
            "default": 25,
            "validation": {
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "pageSizeOptions",
            "type": "number[]",
            "required": false,
            "description": "Available page size choices for the user. Displayed as a dropdown in the pagination bar.\nMust be sorted ascending.\n",
            "default": [
              10,
              25,
              50,
              100
            ],
            "validation": {
              "minItems": 1,
              "uniqueItems": true
            }
          },
          {
            "name": "showPageSizeSelector",
            "type": "boolean",
            "required": false,
            "description": "Whether to display the page size dropdown selector.",
            "default": true
          },
          {
            "name": "showGotoPage",
            "type": "boolean",
            "required": false,
            "description": "Whether to display a \"go to page\" input for direct page navigation.",
            "default": false
          },
          {
            "name": "showItemRange",
            "type": "boolean",
            "required": false,
            "description": "Whether to display the item range indicator (e.g., \"Showing 26-50 of 312\").\n",
            "default": true
          }
        ],
        "schema": {
          "page": {
            "type": "number",
            "required": true,
            "description": "Current page number (1-based).",
            "default": 1,
            "validation": {
              "minimum": 1
            }
          },
          "pageSize": {
            "type": "number",
            "required": true,
            "description": "Number of items displayed per page.",
            "default": 25,
            "validation": {
              "minimum": 1,
              "maximum": 500
            }
          },
          "totalItems": {
            "type": "number",
            "required": false,
            "description": "Total number of items across all pages. Used to compute total page count.",
            "default": 0,
            "validation": {
              "minimum": 0
            }
          },
          "totalPages": {
            "type": "number",
            "required": false,
            "description": "Computed total number of pages (ceil(totalItems / pageSize)).",
            "default": 0,
            "validation": {
              "minimum": 0
            }
          }
        },
        "semantics": {
          "page": {
            "semantic_type": "state.pagination.page",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "PaginationBar",
              "description": "Current active page, drives page button highlight state."
            }
          },
          "pageSize": {
            "semantic_type": "state.pagination.pageSize",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "PaginationBar",
              "defaultParameter": "defaultPageSize"
            }
          },
          "totalItems": {
            "semantic_type": "metric.pagination.totalItems",
            "token_mapping": "tokenMap(pagination.info.*)",
            "ui_hints": {
              "component": "PaginationBar",
              "format": "integer"
            }
          },
          "totalPages": {
            "semantic_type": "metric.pagination.totalPages",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "PaginationBar",
              "description": "Computed from totalItems and pageSize."
            }
          }
        },
        "tokens": {
          "pagination.bar.bg": "var(--sys-surface-secondary)",
          "pagination.bar.border": "var(--sys-border-default)",
          "pagination.button.bg": "var(--sys-surface-default)",
          "pagination.button.text": "var(--sys-text-primary)",
          "pagination.button.hover.bg": "var(--sys-surface-hover)",
          "pagination.button.active.bg": "var(--sys-surface-accent)",
          "pagination.button.active.text": "var(--sys-text-on-accent)",
          "pagination.button.disabled.text": "var(--sys-text-disabled)",
          "pagination.info.text": "var(--sys-text-subtle)",
          "pagination.selector.border": "var(--sys-border-default)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2026-03-05",
          "updated": "2026-03-05",
          "owners": [
            "design@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "PaginationBar supports full keyboard navigation:\n- Tab to move between page buttons, page size selector, and goto input\n- Enter/Space to activate a page button\n- Arrow keys to increment/decrement page in goto input\n- Home/End to jump to first/last page\n",
            "screenreader": "Pagination bar uses nav role with aria-label=\"Pagination\".\nCurrent page announced via aria-current=\"page\".\nPage buttons announce their page number.\nItem range indicator reads \"Showing X to Y of Z items\".\nDisabled prev/next buttons announce as disabled.\n"
          },
          "regionsUsed": [
            "list"
          ],
          "examples": [
            "Product catalog pagination",
            "User directory pagination",
            "Invoice list pagination"
          ],
          "references": [
            "Trait Engine Spec v0.1 section 2"
          ]
        },
        "objects": [
          "Product"
        ],
        "source": "traits/behavioral/Pageable.trait.yaml"
      },
      "Preferenceable": {
        "name": "Preferenceable",
        "version": "1.0.0",
        "description": "User preference trait backed by JSONB storage, schema versioning, and registry governance. Encodes namespaces such as theme, notifications, and display with deterministic overrides.",
        "category": "core",
        "tags": [
          "preferences",
          "jsonb",
          "schema-evolution",
          "user-settings",
          "notification"
        ],
        "contexts": [
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "PreferenceSummaryBadge",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "namespacesField": "preference_namespaces",
              "versionField": "preference_version"
            }
          },
          {
            "component": "PreferencePanel",
            "context": "detail",
            "position": "main",
            "priority": 55,
            "props": {
              "preferencesField": "preference_document",
              "metadataField": "preference_metadata",
              "namespaceField": "preference_namespaces"
            }
          },
          {
            "component": "PreferenceEditor",
            "context": "form",
            "position": "main",
            "priority": null,
            "props": {
              "namespacesField": "preference_namespaces",
              "documentField": "preference_document",
              "registryNamespaceParameter": "registryNamespace"
            }
          }
        ],
        "parameters": [
          {
            "name": "namespaces",
            "type": "string[]",
            "required": true,
            "description": "Allowed top-level namespaces for preference keys (theme, notifications, display, etc.).",
            "default": [
              "theme",
              "notifications",
              "display"
            ],
            "validation": {
              "minItems": 1,
              "maxItems": 12,
              "uniqueItems": true,
              "items": {
                "pattern": "^[a-z0-9._-]+$",
                "minLength": 2,
                "maxLength": 48
              }
            }
          },
          {
            "name": "schemaVersion",
            "type": "string",
            "required": true,
            "description": "Current JSON Schema version served by the registry for validation and UI generation.",
            "default": "1.0.0",
            "validation": {
              "pattern": "^\\d+\\.\\d+\\.\\d+$"
            }
          },
          {
            "name": "allowUnknownNamespaces",
            "type": "boolean",
            "required": false,
            "description": "Escape hatch allowing writes outside the declared namespace allow list.",
            "default": false
          },
          {
            "name": "registryNamespace",
            "type": "string",
            "required": false,
            "description": "Registry identifier used to fetch JSON Schema and uiSchema bundles.",
            "default": "user-preferences",
            "validation": {
              "pattern": "^[a-z0-9._-]+$"
            }
          }
        ],
        "schema": {
          "preference_document": {
            "type": "PreferenceDocument",
            "required": true,
            "description": "Normalized preference payload captured by PreferenceStore (version, preferences map, metadata).",
            "default": {
              "version": "1.0.0",
              "preferences": {
                "theme": {
                  "mode": "system"
                },
                "notifications": {
                  "mention": {
                    "email": true,
                    "push": true
                  }
                }
              },
              "metadata": {
                "schemaVersion": "1.0.0",
                "lastUpdated": "2025-11-18T00:00:00Z",
                "source": "system",
                "migrationApplied": []
              }
            }
          },
          "preference_metadata": {
            "type": "PreferenceMetadata",
            "required": true,
            "description": "Tracks schema version, lastUpdated timestamp, migration records, and source."
          },
          "preference_version": {
            "defaultFromParameter": "schemaVersion",
            "type": "string",
            "required": true,
            "description": "SemVer mirror of preference_document.version for indexing and analytics.",
            "validation": {
              "pattern": "^\\d+\\.\\d+\\.\\d+$"
            }
          },
          "preference_namespaces": {
            "defaultFromParameter": "namespaces",
            "type": "string[]",
            "required": true,
            "description": "Materialized namespace list resolved from parameters/registry for auditing.",
            "default": [
              "theme",
              "notifications",
              "display"
            ]
          },
          "preference_mutations": {
            "type": "number",
            "required": false,
            "description": "Monotonic counter incremented whenever preferences mutate (invalidates caches).",
            "default": 0,
            "validation": {
              "minimum": 0
            }
          }
        },
        "semantics": {
          "preference_document": {
            "semantic_type": "preferences.document",
            "token_mapping": "tokenMap(preferences.document)",
            "ui_hints": {
              "component": "PreferenceDiffPanel",
              "registryNamespaceParameter": "registryNamespace"
            }
          },
          "preference_metadata": {
            "semantic_type": "preferences.metadata",
            "token_mapping": "tokenMap(preferences.metadata)",
            "ui_hints": {
              "component": "PreferenceDiagnostics"
            }
          },
          "preference_version": {
            "semantic_type": "preferences.version",
            "token_mapping": "tokenMap(preferences.version)",
            "ui_hints": {
              "component": "PreferenceVersionBadge"
            }
          },
          "preference_namespaces": {
            "semantic_type": "preferences.namespaces",
            "token_mapping": "tokenMap(preferences.namespaces)",
            "ui_hints": {
              "component": "PreferenceNamespaceChips"
            }
          }
        },
        "tokens": {
          "preferences.panel.bg": "var(--sys-surface-raised)",
          "preferences.panel.border": "var(--sys-border-strong)",
          "preferences.namespace.badge.bg": "var(--sys-surface-muted)",
          "preferences.namespace.badge.text": "var(--sys-text-strong)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-18",
          "owners": [
            "core@oods.systems",
            "platform@oods.systems"
          ],
          "maturity": "experimental",
          "accessibility": {
            "keyboard": "PreferenceEditor supports namespace-by-namespace keyboard traversal with aria landmarks.",
            "screenreader": "PreferencePanel announces namespace and control labels derived from JSON Schema titles."
          },
          "regionsUsed": [
            "list",
            "detail",
            "form"
          ],
          "examples": [
            "User",
            "Subscription"
          ],
          "references": [
            "R21.5 Preferenceable Trait Implementation",
            "objects/provenance.v1.json#/references/ref-2181d6411382"
          ]
        },
        "objects": [
          "Organization",
          "User"
        ],
        "source": "traits/core/Preferenceable.trait.yaml"
      },
      "Priceable": {
        "name": "Priceable",
        "version": "1.0.0",
        "description": "Introduces monetization metadata with currency handling, pricing models, and billing cadence semantics.",
        "category": "financial",
        "tags": [
          "pricing",
          "monetization",
          "commerce",
          "billing"
        ],
        "contexts": [
          "card",
          "detail",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "PriceSummary",
            "context": "detail",
            "position": "top",
            "priority": null,
            "props": {
              "amountField": "unit_amount_cents",
              "currencyField": "currency",
              "modelField": "pricing_model",
              "intervalField": "billing_interval",
              "taxBehaviorField": "tax_behavior"
            }
          },
          {
            "component": "PriceBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "amountField": "unit_amount_cents",
              "currencyField": "currency"
            }
          },
          {
            "component": "PriceBadge",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "amountField": "unit_amount_cents",
              "currencyField": "currency"
            }
          }
        ],
        "parameters": [
          {
            "name": "supportedCurrencies",
            "type": "string[]",
            "required": true,
            "description": "ISO currency codes permitted for pricing this entity.",
            "default": [
              "USD",
              "EUR",
              "GBP"
            ]
          },
          {
            "name": "defaultCurrency",
            "type": "string",
            "required": false,
            "description": "Currency preselected when authoring pricing information.",
            "default": "USD",
            "validation": {
              "enumFromParameter": "supportedCurrencies"
            }
          },
          {
            "name": "pricingModels",
            "type": "string[]",
            "required": true,
            "description": "Supported strategies describing how the entity is monetized.",
            "default": [
              "one_time",
              "subscription",
              "usage_based"
            ]
          },
          {
            "name": "billingIntervals",
            "type": "string[]",
            "required": false,
            "description": "Allowed billing cadences when the pricing model is subscription based.",
            "default": [
              "one_time",
              "day",
              "week",
              "month",
              "year"
            ]
          },
          {
            "name": "taxBehavior",
            "type": "string",
            "required": false,
            "description": "Indicates whether prices are tax inclusive or exclusive.",
            "default": "exclusive",
            "validation": {
              "enum": [
                "exclusive",
                "inclusive"
              ]
            }
          }
        ],
        "schema": {
          "unit_amount_cents": {
            "type": "number",
            "required": true,
            "description": "Base unit price expressed in the smallest currency denomination.",
            "validation": {
              "minimum": 0
            }
          },
          "currency": {
            "type": "string",
            "required": true,
            "description": "ISO currency code for the unit amount.",
            "validation": {
              "enumFromParameter": "supportedCurrencies"
            }
          },
          "pricing_model": {
            "type": "string",
            "required": true,
            "description": "Monetization model applied to the entity.",
            "validation": {
              "enumFromParameter": "pricingModels"
            }
          },
          "billing_interval": {
            "type": "string",
            "required": false,
            "description": "Billing cadence when pricing_model indicates recurring revenue.",
            "validation": {
              "enumFromParameter": "billingIntervals"
            }
          },
          "tax_behavior": {
            "type": "string",
            "required": true,
            "description": "Defines whether taxes are included in the displayed price.",
            "validation": {
              "enum": [
                "exclusive",
                "inclusive"
              ]
            },
            "default": "exclusive"
          }
        },
        "semantics": {
          "unit_amount_cents": {
            "semantic_type": "commerce.price.amount",
            "token_mapping": "tokenMap(commerce.price.primary)",
            "ui_hints": {
              "minorUnits": 100,
              "component": "CurrencyAmount",
              "currencyField": "currency"
            }
          },
          "currency": {
            "semantic_type": "commerce.price.currency",
            "token_mapping": "tokenMap(commerce.currency.primary)",
            "ui_hints": {
              "component": "CurrencyCode",
              "parameterSource": "supportedCurrencies"
            }
          },
          "pricing_model": {
            "semantic_type": "commerce.price.model",
            "token_mapping": "tokenMap(commerce.pricing.model)",
            "ui_hints": {
              "component": "PricingModelBadge",
              "parameterSource": "pricingModels"
            }
          },
          "billing_interval": {
            "semantic_type": "commerce.price.interval",
            "token_mapping": "tokenMap(commerce.pricing.interval)",
            "ui_hints": {
              "component": "BillingIntervalBadge",
              "parameterSource": "billingIntervals"
            }
          },
          "tax_behavior": {
            "semantic_type": "commerce.price.tax_behavior",
            "token_mapping": "tokenMap(commerce.pricing.tax)",
            "ui_hints": {
              "component": "TaxBehaviorTag"
            }
          }
        },
        "tokens": {
          "commerce.price.text": "var(--text-strong)",
          "commerce.price.badge.bg": "var(--surface-accent)",
          "commerce.pricing.model.text": "var(--text-default)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-10-16",
          "owners": [
            "commerce@oods.systems",
            "finance@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "n/a",
            "screenreader": "Announces price, currency, billing interval, and tax behavior."
          },
          "regionsUsed": [
            "detail",
            "list",
            "card"
          ],
          "examples": [
            "Product",
            "Subscription"
          ],
          "references": [
            "Trait Engine Spec v0.1 §2"
          ]
        },
        "objects": [
          "Product",
          "Transaction"
        ],
        "source": "traits/financial/Priceable.trait.yaml"
      },
      "Provenanced": {
        "name": "Provenanced",
        "version": "1.0.0",
        "description": "Carries how a record's values were obtained, beside the values, wherever the record travels.\n\nTwo values obtained differently are not comparable: a route an agent inferred from a URL and a route an\nOpenAPI document declares can hold the same string and mean different things, and a screen that shows\none beside the other unlabelled publishes a false equivalence. A captured finding is only as good as the\nengine, the version, the file and the moment behind it.\n\nOODS Foundry already carries this shape twice, and this trait is factored from them rather than inventing a\nthird. The observation rows name the capture run, the target, the artifact kind and read path, and the\ncapture time beside each row; the preview's context panel names each item's source, id, the query that\nfound it and when it was fetched. What both say is the same five things: which source, which record\nin it, where in that record, how, and when. Those are the five fields here:\n\n  provenance_source   who produced it            observation: the capture tool  context: source\n  provenance_record   which record there         observation: runId           context: id\n  provenance_locator  where in that record       observation: readPath        context: query\n  provenance_method   how the value was obtained  observation: artifactKind   context: (the search)\n  provenance_at       when                        observation: capturedAt      context: fetchedAt\n\nThe method is the field that separates this from a citation: \"axe-core 4.11.0\", \"route_derived\",\n\"openapi_declared\", \"sha256 attested by the run manifest\". The observation rows and context items keep\ntheir own stored shapes for now.\n\nAn absent value means not recorded, never \"no provenance needed\". A record with no provenance_source\nis not shown as sourced.",
        "category": "core",
        "tags": [
          "provenance",
          "evidence",
          "lineage",
          "citation"
        ],
        "contexts": [
          "card",
          "detail",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "Text",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "field": "provenance_method",
              "label": "Obtained by"
            }
          },
          {
            "component": "RelativeTimestamp",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "field": "provenance_at",
              "label": "Obtained"
            }
          },
          {
            "component": "RelativeTimestamp",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "field": "provenance_at"
            }
          },
          {
            "component": "Text",
            "context": "detail",
            "position": "main",
            "priority": 66,
            "props": {
              "field": "provenance_source",
              "label": "Source"
            }
          },
          {
            "component": "Text",
            "context": "detail",
            "position": "main",
            "priority": 65,
            "props": {
              "field": "provenance_method",
              "label": "Obtained by"
            }
          },
          {
            "component": "Text",
            "context": "detail",
            "position": "main",
            "priority": 64,
            "props": {
              "field": "provenance_locator",
              "label": "Read from"
            }
          },
          {
            "component": "Text",
            "context": "detail",
            "position": "main",
            "priority": 63,
            "props": {
              "field": "provenance_record",
              "label": "Record"
            }
          }
        ],
        "parameters": [
          {
            "name": "source",
            "type": "string",
            "required": true,
            "description": "The producing system every record of this object comes from, shown as recorded (e.g. a capture tool)."
          },
          {
            "name": "methodLabel",
            "type": "string",
            "required": false,
            "description": "Visible wording beside the method, so the screen says how rather than showing a bare token.",
            "default": "Obtained by"
          }
        ],
        "schema": {
          "provenance_source": {
            "type": "string",
            "required": true,
            "description": "The system that produced the record, such as a capture tool."
          },
          "provenance_record": {
            "type": "string",
            "required": true,
            "description": "Which record in that system — a run id, an item id."
          },
          "provenance_locator": {
            "type": "string",
            "required": false,
            "description": "Where in that record the value was read — a file path under the run, a query."
          },
          "provenance_method": {
            "type": "string",
            "required": true,
            "description": "How the value was obtained — the engine and its version, the inference, the declaration, the\nattestation. Two values with different methods are not presented as the same kind of fact.\n"
          },
          "provenance_at": {
            "type": "datetime",
            "required": true,
            "description": "When it was obtained.",
            "validation": {
              "format": "date-time"
            }
          }
        },
        "semantics": {
          "provenance_source": {
            "semantic_type": "provenance.source",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "Text"
            }
          },
          "provenance_record": {
            "semantic_type": "provenance.record",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "Text"
            }
          },
          "provenance_locator": {
            "semantic_type": "provenance.locator",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "Text"
            }
          },
          "provenance_method": {
            "semantic_type": "provenance.method",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "Text"
            }
          },
          "provenance_at": {
            "semantic_type": "provenance.at",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "RelativeTimestamp"
            }
          }
        },
        "tokens": {},
        "dependencies": [],
        "metadata": {
          "created": "2026-09-18",
          "updated": "2026-09-18",
          "owners": [
            "core@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "keyboard": "Provenance adds no interactive control; it renders as labelled text.",
            "screenreader": "Each value is read with its visible label (\"Obtained by axe-core 4.11.0\")."
          },
          "regionsUsed": [
            "list",
            "card",
            "detail"
          ],
          "examples": [
            "Finding",
            "Run",
            "CapturedArtifact"
          ],
          "references": [
            "objects/provenance.v1.json#/references/ref-55ab62519302 — observation rows: runId, target, artifactKind, readPath, capturedAt",
            "objects/provenance.v1.json#/references/ref-38c48888c8fe — context items: source, id, query, fetchedAt"
          ]
        },
        "objects": [],
        "source": "traits/core/Provenanced.trait.yaml"
      },
      "SaaSBillingBillable": {
        "name": "SaaSBillingBillable",
        "version": "1.0.0",
        "description": "Normalizes recurring price configuration for SaaS plans including cadence, currency, and trial policy. NOTE (trait-split gap): this domain trait does NOT model proration — no supportProration/proration_amount/proration_date/prorationBehavior. A Subscription composing only SaaSBillingBillable silently cannot prorate. To enable proration, compose the CORE financial/Billable trait (which owns the proration semantics). See traits/financial/Billable.trait.yaml.",
        "category": "domain",
        "tags": [
          "billing",
          "pricing",
          "domain"
        ],
        "contexts": [
          "card",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "BillingSummaryBadge",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "amountField": "amount_minor",
              "currencyField": "currency",
              "intervalField": "billing_interval",
              "minorUnits": 100
            }
          },
          {
            "component": "BillingCardMeta",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "amountField": "amount_minor",
              "currencyField": "currency",
              "intervalField": "billing_interval",
              "minorUnits": 100
            }
          }
        ],
        "parameters": [
          {
            "name": "defaultCurrency",
            "type": "string",
            "required": false,
            "description": "ISO 4217 currency used when a plan omits currency.",
            "default": "usd"
          },
          {
            "name": "supportedIntervals",
            "type": "string[]",
            "required": false,
            "description": "Allowed billing intervals that downstream plans may select.",
            "default": [
              "monthly",
              "quarterly",
              "annual"
            ]
          },
          {
            "name": "decimalPrecision",
            "type": "number",
            "required": false,
            "description": "Minor unit precision (ex: cents = 2, yen = 0).",
            "default": 2
          }
        ],
        "schema": {
          "plan_code": {
            "type": "string",
            "required": true,
            "description": "Provider specific identifier for the plan or price."
          },
          "plan_name": {
            "type": "string",
            "required": true,
            "description": "Human readable plan label rendered in list and detail contexts."
          },
          "billing_interval": {
            "type": "string",
            "required": true,
            "description": "Billing cadence name selected from supportedIntervals.",
            "validation": {
              "enumFromParameter": "supportedIntervals"
            }
          },
          "interval_count": {
            "type": "integer",
            "required": false,
            "description": "Multiplier for interval (ex: 12 with monthly => yearly cadence).",
            "default": 1
          },
          "amount_minor": {
            "type": "integer",
            "required": true,
            "description": "Contract value expressed in minor currency units."
          },
          "currency": {
            "type": "string",
            "required": true,
            "description": "ISO 4217 currency for the plan price.",
            "defaultFromParameter": "defaultCurrency"
          },
          "trial_period_days": {
            "type": "integer",
            "required": false,
            "description": "Length of introductory trial period in days."
          },
          "collection_method": {
            "type": "string",
            "required": false,
            "description": "How billing is collected (charge_automatically, send_invoice)."
          },
          "billing_anchor_day": {
            "type": "integer",
            "required": false,
            "description": "Day of month used to anchor renewals when prorating.",
            "validation": {
              "minimum": 1,
              "maximum": 31
            }
          },
          "pricing_model": {
            "type": "string",
            "required": false,
            "description": "Price strategy (flat, per_unit, tiered, package).",
            "default": "flat"
          }
        },
        "semantics": {
          "plan_code": {
            "semantic_type": "billing.plan.code",
            "token_mapping": "tokenMap(billing.plan.code)"
          },
          "plan_name": {
            "semantic_type": "billing.plan.name",
            "token_mapping": "tokenMap(billing.plan.name)"
          },
          "billing_interval": {
            "semantic_type": "billing.plan.interval",
            "token_mapping": "tokenMap(billing.plan.interval)"
          },
          "interval_count": {
            "semantic_type": "billing.plan.interval_count",
            "token_mapping": "tokenMap(billing.plan.interval_count)"
          },
          "amount_minor": {
            "semantic_type": "billing.plan.amount_minor",
            "token_mapping": "tokenMap(billing.plan.amount_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "currency": {
            "semantic_type": "billing.plan.currency",
            "token_mapping": "tokenMap(billing.plan.currency)"
          },
          "trial_period_days": {
            "semantic_type": "billing.plan.trial_period_days",
            "token_mapping": "tokenMap(billing.plan.trial_period_days)"
          },
          "collection_method": {
            "semantic_type": "billing.plan.collection_method",
            "token_mapping": "tokenMap(billing.plan.collection_method)"
          },
          "billing_anchor_day": {
            "semantic_type": "billing.plan.billing_anchor_day",
            "token_mapping": "tokenMap(billing.plan.billing_anchor_day)"
          },
          "pricing_model": {
            "semantic_type": "billing.plan.pricing_model",
            "token_mapping": "tokenMap(billing.plan.pricing_model)"
          }
        },
        "tokens": {
          "billing.plan.name": "var(--cmp-text-strong)",
          "billing.plan.amount_minor": "var(--cmp-text-body-strong)",
          "billing.plan.currency": "var(--cmp-text-subtle)",
          "billing.plan.interval": "var(--cmp-text-subtle)",
          "billing.plan.collection_method": "var(--cmp-badge-text-info)"
        },
        "dependencies": [],
        "metadata": {
          "owners": [
            "billing@oods.systems",
            "design@oods.systems"
          ],
          "maturity": "beta",
          "regionsUsed": [
            "list",
            "card"
          ],
          "references": [
            {
              "R13.5 Canonical Model": "Subscription and Invoice"
            },
            "R4.5 SaaS Enum-to-Token Mapping Schema"
          ]
        },
        "objects": [
          "Plan"
        ],
        "source": "domains/saas-billing/traits/billable.trait.yaml"
      },
      "SaaSBillingMetered": {
        "name": "SaaSBillingMetered",
        "version": "1.0.0",
        "description": "Provides usage metering fields for consumption based billing with normalized units and rollover policy.",
        "category": "domain",
        "tags": [
          "billing",
          "usage",
          "domain"
        ],
        "contexts": [],
        "viewExtensions": [],
        "parameters": [
          {
            "name": "unit",
            "type": "string",
            "required": true,
            "description": "Canonical usage unit label (ex: seats, credits, api_calls).",
            "default": "seats"
          },
          {
            "name": "rolloverStrategy",
            "type": "string",
            "required": false,
            "description": "Determines how unused units are treated at period end.",
            "default": "none",
            "validation": {
              "enum": [
                "none",
                "carry_forward",
                "expire"
              ]
            }
          },
          {
            "name": "sampleWindowDays",
            "type": "integer",
            "required": false,
            "description": "Rolling window size used to calculate usage deltas.",
            "default": 30
          }
        ],
        "schema": {
          "meter_name": {
            "type": "string",
            "required": true,
            "description": "Friendly metered feature name shown in UI (ex: Analytics Seats)."
          },
          "included_quantity": {
            "type": "integer",
            "required": true,
            "description": "Quantity included in base plan before overages."
          },
          "consumed_quantity": {
            "type": "integer",
            "required": true,
            "description": "Actual quantity consumed in the active period."
          },
          "unit_label": {
            "type": "string",
            "required": true,
            "description": "Label for display, defaults to the unit parameter.",
            "defaultFromParameter": "unit"
          },
          "period_start": {
            "type": "date",
            "required": true,
            "description": "Date the usage accumulation window began."
          },
          "period_end": {
            "type": "date",
            "required": true,
            "description": "Date the usage accumulation window ends."
          },
          "rollover_strategy": {
            "type": "string",
            "required": false,
            "description": "Strategy for unused units (inherits rolloverStrategy parameter).",
            "defaultFromParameter": "rolloverStrategy"
          },
          "overage_rate_minor": {
            "type": "integer",
            "required": false,
            "description": "Cost per additional unit expressed in minor currency units."
          },
          "projected_overage_minor": {
            "type": "integer",
            "required": false,
            "description": "Forecasted overage spend derived from consumption trends."
          },
          "samples": {
            "type": "UsageSample[]",
            "required": false,
            "description": "Rolling usage measurements for charts or anomaly detection.",
            "default": []
          }
        },
        "semantics": {
          "meter_name": {
            "semantic_type": "billing.usage.meter_name",
            "token_mapping": "tokenMap(billing.usage.meter_name)"
          },
          "included_quantity": {
            "semantic_type": "billing.usage.included_quantity",
            "token_mapping": "tokenMap(billing.usage.included_quantity)",
            "ui_hints": {
              "format": "quantity"
            }
          },
          "consumed_quantity": {
            "semantic_type": "billing.usage.consumed_quantity",
            "token_mapping": "tokenMap(billing.usage.consumed_quantity)",
            "ui_hints": {
              "format": "quantity"
            }
          },
          "unit_label": {
            "semantic_type": "billing.usage.unit_label",
            "token_mapping": "tokenMap(billing.usage.unit_label)"
          },
          "period_start": {
            "semantic_type": "billing.usage.period_start",
            "token_mapping": "tokenMap(billing.usage.period_start)"
          },
          "period_end": {
            "semantic_type": "billing.usage.period_end",
            "token_mapping": "tokenMap(billing.usage.period_end)"
          },
          "rollover_strategy": {
            "semantic_type": "billing.usage.rollover_strategy",
            "token_mapping": "tokenMap(billing.usage.rollover_strategy)"
          },
          "overage_rate_minor": {
            "semantic_type": "billing.usage.overage_rate_minor",
            "token_mapping": "tokenMap(billing.usage.overage_rate_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "projected_overage_minor": {
            "semantic_type": "billing.usage.projected_overage_minor",
            "token_mapping": "tokenMap(billing.usage.projected_overage_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "samples": {
            "semantic_type": "billing.usage.samples",
            "token_mapping": "tokenMap(billing.usage.samples)"
          }
        },
        "tokens": {
          "billing.usage.meter_name": "var(--cmp-text-strong)",
          "billing.usage.consumed_quantity": "var(--cmp-text-accent)",
          "billing.usage.projected_overage_minor": "var(--cmp-text-warning)"
        },
        "dependencies": [],
        "metadata": {
          "owners": [
            "product-analytics@oods.systems"
          ],
          "maturity": "beta",
          "references": [
            {
              "R13.5 Canonical Model": "Subscription and Invoice"
            }
          ]
        },
        "objects": [
          "Plan",
          "Usage"
        ],
        "source": "domains/saas-billing/traits/metered.trait.yaml"
      },
      "SaaSBillingPayable": {
        "name": "SaaSBillingPayable",
        "version": "1.0.0",
        "description": "Captures invoice level billing terms, status, and outstanding balance metadata for SaaS finance teams.",
        "category": "domain",
        "tags": [
          "billing",
          "invoice",
          "domain"
        ],
        "contexts": [
          "card",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "BillingSummaryBadge",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "amountField": "total_minor",
              "currencyField": "currency",
              "minorUnits": 100,
              "showInterval": false
            }
          },
          {
            "component": "BillingSummaryBadge",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "amountField": "total_minor",
              "currencyField": "currency",
              "minorUnits": 100,
              "showInterval": false
            }
          }
        ],
        "parameters": [
          {
            "name": "statusEnum",
            "type": "string[]",
            "required": true,
            "description": "Canonical invoice status values allowed by the domain.",
            "default": [
              "draft",
              "posted",
              "open",
              "processing",
              "past_due",
              "paid",
              "refunded",
              "uncollectible",
              "void"
            ]
          },
          {
            "name": "paymentTerms",
            "type": "string[]",
            "required": false,
            "description": "Supported payment term descriptors (ex: net_15, due_upon_receipt).",
            "default": [
              "due_upon_receipt",
              "net_15",
              "net_30",
              "net_45"
            ]
          }
        ],
        "schema": {
          "invoice_number": {
            "type": "string",
            "required": true,
            "description": "Human readable invoice identifier presented to customers."
          },
          "status": {
            "type": "string",
            "required": true,
            "description": "Canonical invoice status after provider mapping.",
            "validation": {
              "enumFromParameter": "statusEnum"
            }
          },
          "provider_status": {
            "type": "string",
            "required": false,
            "description": "Original provider reported status or badge."
          },
          "issued_at": {
            "type": "datetime",
            "required": true,
            "description": "Timestamp when the invoice was finalized or posted."
          },
          "due_at": {
            "type": "datetime",
            "required": false,
            "description": "Payment due timestamp derived from payment terms."
          },
          "paid_at": {
            "type": "datetime",
            "required": false,
            "description": "Timestamp when full payment cleared."
          },
          "total_minor": {
            "type": "integer",
            "required": true,
            "description": "Total amount due expressed in minor currency units."
          },
          "balance_minor": {
            "type": "integer",
            "required": false,
            "description": "Remaining amount outstanding in minor units.",
            "default": 0
          },
          "currency": {
            "type": "string",
            "required": true,
            "description": "ISO 4217 currency for the invoice."
          },
          "payment_terms": {
            "type": "string",
            "required": false,
            "description": "Payment term label describing when payment is expected.",
            "validation": {
              "enumFromParameter": "paymentTerms"
            }
          },
          "collection_state": {
            "type": "string",
            "required": false,
            "description": "Dunning phase or retry program detail presented to success teams."
          },
          "last_reminder_at": {
            "type": "datetime",
            "required": false,
            "description": "Timestamp of most recent payment reminder issued to customer."
          },
          "aging_bucket_days": {
            "type": "integer",
            "required": false,
            "description": "Number of days outstanding grouped for aging reports."
          },
          "attempt_count": {
            "type": "integer",
            "required": false,
            "description": "Number of automatic payment attempts made on this invoice (Stripe smart-retries attempt_count). Increments on each retry in the dunning window. Source: docs.stripe.com/billing/revenue-recovery/smart-retries.",
            "default": 0,
            "validation": {
              "minimum": 0
            }
          },
          "next_payment_attempt": {
            "type": "datetime",
            "required": false,
            "description": "When the next automatic payment retry is scheduled (Stripe smart-retries next_payment_attempt). Defines the open end of the retry window — modeled on the Refundable.refundable_until datetime-window precedent. Absent/null when no further attempts are scheduled (retries exhausted → invoice goes uncollectible, mirroring the subscription `unpaid` state). Source: docs.stripe.com/billing/revenue-recovery/smart-retries."
          },
          "memo": {
            "type": "string",
            "required": false,
            "description": "Internal finance note or customer visible memo."
          }
        },
        "semantics": {
          "invoice_number": {
            "semantic_type": "billing.invoice.number",
            "token_mapping": "tokenMap(billing.invoice.number)"
          },
          "status": {
            "semantic_type": "billing.invoice.status",
            "token_mapping": "tokenMap(billing.invoice.status.*)"
          },
          "provider_status": {
            "semantic_type": "billing.invoice.provider_status",
            "token_mapping": "tokenMap(billing.invoice.provider_status)"
          },
          "issued_at": {
            "semantic_type": "billing.invoice.issued_at",
            "token_mapping": "tokenMap(billing.invoice.issued_at)"
          },
          "due_at": {
            "semantic_type": "billing.invoice.due_at",
            "token_mapping": "tokenMap(billing.invoice.due_at)"
          },
          "paid_at": {
            "semantic_type": "billing.invoice.paid_at",
            "token_mapping": "tokenMap(billing.invoice.paid_at)"
          },
          "total_minor": {
            "semantic_type": "billing.invoice.total_minor",
            "token_mapping": "tokenMap(billing.invoice.total_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "balance_minor": {
            "semantic_type": "billing.invoice.balance_minor",
            "token_mapping": "tokenMap(billing.invoice.balance_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "currency": {
            "semantic_type": "billing.invoice.currency",
            "token_mapping": "tokenMap(billing.invoice.currency)"
          },
          "payment_terms": {
            "semantic_type": "billing.invoice.payment_terms",
            "token_mapping": "tokenMap(billing.invoice.payment_terms)"
          },
          "collection_state": {
            "semantic_type": "billing.invoice.collection_state",
            "token_mapping": "tokenMap(billing.invoice.collection_state)"
          },
          "last_reminder_at": {
            "semantic_type": "billing.invoice.last_reminder_at",
            "token_mapping": "tokenMap(billing.invoice.last_reminder_at)"
          },
          "aging_bucket_days": {
            "semantic_type": "billing.invoice.aging_bucket_days",
            "token_mapping": "tokenMap(billing.invoice.aging_bucket_days)"
          },
          "attempt_count": {
            "semantic_type": "billing.invoice.attempt_count",
            "token_mapping": "tokenMap(billing.invoice.attempt_count)"
          },
          "next_payment_attempt": {
            "semantic_type": "billing.invoice.next_payment_attempt",
            "token_mapping": "tokenMap(billing.invoice.next_payment_attempt)"
          },
          "memo": {
            "semantic_type": "billing.invoice.memo",
            "token_mapping": "tokenMap(billing.invoice.memo)"
          }
        },
        "tokens": {
          "billing.invoice.number": "var(--cmp-text-strong)",
          "billing.invoice.total_minor": "var(--cmp-text-body-strong)",
          "billing.invoice.balance_minor": "var(--cmp-text-warning)",
          "billing.invoice.status.past_due": "var(--cmp-status-critical-text)",
          "billing.invoice.status.paid": "var(--cmp-status-success-text)"
        },
        "dependencies": [],
        "metadata": {
          "owners": [
            "revenue-ops@oods.systems"
          ],
          "maturity": "beta",
          "regionsUsed": [
            "list",
            "card"
          ],
          "notes": [
            "Canonical status options sourced from r4.5 mapping research.",
            "Dunning/access reconciliation (s126-m05, scoped to the access-revocation need): the 9-value statusEnum is a SUPERSET of the canonical 5-state invoice model (draft, posted, paid, past_due, void — see docs/billing/lifecycle-states.md). Dunning-relevant mapping: `open`/`processing` = pre-dunning (awaiting/settling payment); `past_due` = overdue, retries ongoing → subscription past_due (GRACE, keep access); `uncollectible` = retries exhausted → mirrors subscription `unpaid` (REVOKE access). The retry window is carried by attempt_count + next_payment_attempt. The subscription-status → access decision is encoded in src/domain/billing/states.ts hasServiceAccess()."
          ]
        },
        "objects": [
          "Invoice"
        ],
        "source": "domains/saas-billing/traits/payable.trait.yaml"
      },
      "SaaSBillingRefundable": {
        "name": "SaaSBillingRefundable",
        "version": "1.0.0",
        "description": "Describes refund eligibility, policy windows, and credit memo tracking for SaaS billing flows.",
        "category": "domain",
        "tags": [
          "billing",
          "refund",
          "domain"
        ],
        "contexts": [],
        "viewExtensions": [],
        "parameters": [
          {
            "name": "defaultWindowDays",
            "type": "integer",
            "required": false,
            "description": "Default number of days after payment where refunds are allowed.",
            "default": 30
          },
          {
            "name": "creditMemoTypes",
            "type": "string[]",
            "required": false,
            "description": "Supported credit memo categories used by finance teams.",
            "default": [
              "service_failure",
              "retention_incentive",
              "goodwill"
            ]
          }
        ],
        "schema": {
          "refundable_until": {
            "type": "datetime",
            "required": false,
            "description": "Date when refund eligibility window ends for this record."
          },
          "refund_policy_url": {
            "type": "string",
            "required": false,
            "description": "Link to customer facing refund or cancellation policy."
          },
          "total_refunded_minor": {
            "type": "integer",
            "required": false,
            "description": "Cumulative amount refunded in minor currency units.",
            "default": 0
          },
          "credit_memo_balance_minor": {
            "type": "integer",
            "required": false,
            "description": "Remaining credit memo balance that can be applied to invoices.",
            "default": 0
          },
          "credit_memo_type": {
            "type": "string",
            "required": false,
            "description": "Category of credit memo tied to business justification.",
            "validation": {
              "enumFromParameter": "creditMemoTypes"
            }
          },
          "last_refund_at": {
            "type": "datetime",
            "required": false,
            "description": "Timestamp when the most recent refund was issued."
          },
          "requires_manager_approval": {
            "type": "boolean",
            "required": false,
            "description": "Indicates if finance manager approval is required before issuing refund.",
            "default": false
          },
          "notes": {
            "type": "string",
            "required": false,
            "description": "Internal commentary about refund actions or policy exceptions."
          }
        },
        "semantics": {
          "refundable_until": {
            "semantic_type": "billing.refund.window_end",
            "token_mapping": "tokenMap(billing.refund.window_end)"
          },
          "refund_policy_url": {
            "semantic_type": "billing.refund.policy_link",
            "token_mapping": "tokenMap(billing.refund.policy_link)"
          },
          "total_refunded_minor": {
            "semantic_type": "billing.refund.total_minor",
            "token_mapping": "tokenMap(billing.refund.total_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "credit_memo_balance_minor": {
            "semantic_type": "billing.refund.credit_memo_balance_minor",
            "token_mapping": "tokenMap(billing.refund.credit_memo_balance_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "credit_memo_type": {
            "semantic_type": "billing.refund.credit_memo_type",
            "token_mapping": "tokenMap(billing.refund.credit_memo_type)"
          },
          "last_refund_at": {
            "semantic_type": "billing.refund.last_refund_at",
            "token_mapping": "tokenMap(billing.refund.last_refund_at)"
          },
          "requires_manager_approval": {
            "semantic_type": "billing.refund.requires_manager_approval",
            "token_mapping": "tokenMap(billing.refund.requires_manager_approval)"
          },
          "notes": {
            "semantic_type": "billing.refund.notes",
            "token_mapping": "tokenMap(billing.refund.notes)"
          }
        },
        "tokens": {
          "billing.refund.total_minor": "var(--cmp-text-accent)",
          "billing.refund.credit_memo_balance_minor": "var(--cmp-text-info)",
          "billing.refund.requires_manager_approval": "var(--cmp-badge-text-warning)"
        },
        "dependencies": [],
        "metadata": {
          "owners": [
            "finance@oods.systems"
          ],
          "maturity": "experimental",
          "notes": [
            "Aligns with refund governance requirements captured in billing domain research."
          ]
        },
        "objects": [
          "Invoice"
        ],
        "source": "domains/saas-billing/traits/refundable.trait.yaml"
      },
      "ScaleLinear": {
        "name": "ScaleLinear",
        "version": "0.2.0",
        "description": "Shared linear/continuous scale definition used by positional, color, and\nsize encodings. Provides normalized domain/range metadata plus zero baseline\nenforcement per RDV.3 findings.",
        "category": "viz.scale",
        "tags": [
          "viz",
          "scale",
          "linear"
        ],
        "contexts": [
          "detail",
          "form"
        ],
        "viewExtensions": [
          {
            "component": "VizScaleSummary",
            "context": "detail",
            "position": "sidebar",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "type": "linear",
              "domainMinField": "viz_scale_linear_domain_min",
              "domainMaxField": "viz_scale_linear_domain_max",
              "modeField": "viz_scale_linear_mode",
              "zeroField": "viz_scale_linear_zero_baseline"
            }
          },
          {
            "component": "VizScaleControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "type": "linear",
              "domainMinField": "viz_scale_linear_domain_min",
              "domainMaxField": "viz_scale_linear_domain_max",
              "rangeMinField": "viz_scale_linear_range_min",
              "rangeMaxField": "viz_scale_linear_range_max",
              "zeroField": "viz_scale_linear_zero_baseline",
              "modeField": "viz_scale_linear_mode"
            }
          }
        ],
        "parameters": [
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "domainMin",
            "type": "number",
            "required": true,
            "description": "Default lower domain bound applied when unspecified.",
            "default": 0
          },
          {
            "name": "domainMax",
            "type": "number",
            "required": true,
            "description": "Default upper domain bound applied when unspecified.",
            "default": 1
          },
          {
            "name": "rangeMin",
            "type": "number",
            "required": true,
            "description": "Default lower range bound (normalized 0-1).",
            "default": 0
          },
          {
            "name": "rangeMax",
            "type": "number",
            "required": true,
            "description": "Default upper range bound (normalized 0-1).",
            "default": 1
          },
          {
            "name": "clamp",
            "type": "boolean",
            "required": false,
            "description": "Whether values outside the domain should clamp to edges.",
            "default": true
          },
          {
            "name": "zeroBaseline",
            "type": "boolean",
            "required": false,
            "description": "Forces zero to be included in the domain.",
            "default": true
          },
          {
            "name": "mode",
            "type": "string",
            "required": false,
            "description": "Whether this scale behaves as continuous or band for categories.",
            "default": "continuous",
            "validation": {
              "enum": [
                "continuous",
                "band"
              ]
            }
          }
        ],
        "schema": {
          "viz_scale_linear_domain_min": {
            "type": "number",
            "required": true,
            "description": "Lower domain bound for continuous encodings.",
            "defaultFromParameter": "domainMin"
          },
          "viz_scale_linear_domain_max": {
            "type": "number",
            "required": true,
            "description": "Upper domain bound for continuous encodings.",
            "defaultFromParameter": "domainMax"
          },
          "viz_scale_linear_range_min": {
            "type": "number",
            "required": true,
            "description": "Lower range bound (normalized 0-1).",
            "defaultFromParameter": "rangeMin"
          },
          "viz_scale_linear_range_max": {
            "type": "number",
            "required": true,
            "description": "Upper range bound (normalized 0-1).",
            "defaultFromParameter": "rangeMax"
          },
          "viz_scale_linear_clamp": {
            "type": "boolean",
            "required": false,
            "description": "Indicates whether values outside the domain clamp to bounds.",
            "defaultFromParameter": "clamp"
          },
          "viz_scale_linear_zero_baseline": {
            "type": "boolean",
            "required": false,
            "description": "Forces zero within the domain for accessibility compliance.",
            "defaultFromParameter": "zeroBaseline"
          },
          "viz_scale_linear_mode": {
            "type": "string",
            "required": false,
            "description": "Distinguishes continuous vs band heuristics.",
            "defaultFromParameter": "mode",
            "validation": {
              "enum": [
                "continuous",
                "band"
              ]
            }
          },
          "viz_scale_linear_description": {
            "type": "string",
            "required": false,
            "description": "Narrative summary for fallbacks.",
            "default": "Linear scale with governed domain/range."
          }
        },
        "semantics": {
          "viz_scale_linear_domain_min": {
            "semantic_type": "viz.scale.domain",
            "token_mapping": "tokenMap(viz.scale.domain)",
            "ui_hints": {
              "component": "NumericPreview"
            }
          },
          "viz_scale_linear_domain_max": {
            "semantic_type": "viz.scale.domain",
            "token_mapping": "tokenMap(viz.scale.domain)",
            "ui_hints": {
              "component": "NumericPreview"
            }
          },
          "viz_scale_linear_mode": {
            "semantic_type": "viz.scale.mode",
            "token_mapping": "tokenMap(viz.scale.mode)",
            "ui_hints": {
              "component": "TextBadge"
            }
          },
          "viz_scale_linear_zero_baseline": {
            "semantic_type": "viz.scale.zero",
            "token_mapping": "tokenMap(viz.scale.zero)",
            "ui_hints": {
              "component": "BooleanBadge"
            }
          }
        },
        "tokens": {
          "viz.scale.linear.grid": "var(--cmp-viz-grid-line)",
          "viz.scale.linear.axis": "var(--cmp-viz-axis-line)",
          "viz.scale.linear.zero": "var(--cmp-viz-zero-line)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-02-28",
          "owners": [
            "viz@oods.systems",
            "platform@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "keyboard": "Scale controls are keyboard-operable in VizScaleControls form component.",
            "screenreader": "Scale summary announces domain range and zero baseline status."
          },
          "regionsUsed": [
            "detail",
            "form"
          ],
          "allows": [
            "EncodingPositionX",
            "EncodingPositionY",
            "EncodingSize",
            "EncodingColor"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/scale-linear.trait.yaml"
      },
      "ScaleTemporal": {
        "name": "ScaleTemporal",
        "version": "0.3.0",
        "description": "Temporal scale metadata with UTC rendering. Version 0.3.0 removes the unused\ntimezone parameter (breaking); axes and tooltips continue to render in UTC.",
        "category": "viz.scale",
        "tags": [
          "viz",
          "scale",
          "temporal"
        ],
        "contexts": [
          "detail",
          "form"
        ],
        "viewExtensions": [
          {
            "component": "VizScaleSummary",
            "context": "detail",
            "position": "sidebar",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "type": "temporal",
              "domainMinField": "viz_scale_temporal_domain_start",
              "domainMaxField": "viz_scale_temporal_domain_end",
              "niceField": "viz_scale_temporal_nice"
            }
          },
          {
            "component": "VizScaleControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent",
              "type": "temporal",
              "domainMinField": "viz_scale_temporal_domain_start",
              "domainMaxField": "viz_scale_temporal_domain_end",
              "rangeMinField": "viz_scale_temporal_range_min",
              "rangeMaxField": "viz_scale_temporal_range_max",
              "niceField": "viz_scale_temporal_nice",
              "formatField": "viz_scale_temporal_output_format"
            }
          }
        ],
        "parameters": [
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment for the governed authoring recipes. Data rows remain a consumer operand."
          },
          {
            "name": "domainStart",
            "type": "string",
            "required": true,
            "description": "ISO-8601 timestamp representing the lower bound.",
            "default": "2024-01-01T00:00:00Z"
          },
          {
            "name": "domainEnd",
            "type": "string",
            "required": true,
            "description": "ISO-8601 timestamp representing the upper bound.",
            "default": "2024-12-31T23:59:59Z"
          },
          {
            "name": "rangeMin",
            "type": "number",
            "required": true,
            "description": "Normalized lower range bound (0-1).",
            "default": 0
          },
          {
            "name": "rangeMax",
            "type": "number",
            "required": true,
            "description": "Normalized upper range bound (0-1).",
            "default": 1
          },
          {
            "name": "nice",
            "type": "string",
            "required": false,
            "description": "Interval used when rounding ticks.",
            "default": "month",
            "validation": {
              "enum": [
                "day",
                "week",
                "month",
                "quarter",
                "year"
              ]
            }
          },
          {
            "name": "outputFormat",
            "type": "string",
            "required": false,
            "description": "Default date format string for axes + fallbacks.",
            "default": "YYYY-MM-DD"
          }
        ],
        "schema": {
          "viz_scale_temporal_domain_start": {
            "type": "string",
            "required": true,
            "description": "ISO timestamp representing lower bound.",
            "defaultFromParameter": "domainStart"
          },
          "viz_scale_temporal_domain_end": {
            "type": "string",
            "required": true,
            "description": "ISO timestamp representing upper bound.",
            "defaultFromParameter": "domainEnd"
          },
          "viz_scale_temporal_range_min": {
            "type": "number",
            "required": true,
            "description": "Normalized lower range bound.",
            "defaultFromParameter": "rangeMin"
          },
          "viz_scale_temporal_range_max": {
            "type": "number",
            "required": true,
            "description": "Normalized upper range bound.",
            "defaultFromParameter": "rangeMax"
          },
          "viz_scale_temporal_nice": {
            "type": "string",
            "required": false,
            "description": "Interval used when rounding ticks.",
            "defaultFromParameter": "nice",
            "validation": {
              "enum": [
                "day",
                "week",
                "month",
                "quarter",
                "year"
              ]
            }
          },
          "viz_scale_temporal_output_format": {
            "type": "string",
            "required": false,
            "description": "Default format string for textual output.",
            "defaultFromParameter": "outputFormat"
          },
          "viz_scale_temporal_description": {
            "type": "string",
            "required": false,
            "description": "Narrative summary for fallback contexts.",
            "default": "Temporal scale rendered in UTC."
          }
        },
        "semantics": {
          "viz_scale_temporal_domain_start": {
            "semantic_type": "viz.scale.domain",
            "token_mapping": "tokenMap(viz.scale.domain)",
            "ui_hints": {
              "component": "TimestampPreview"
            }
          },
          "viz_scale_temporal_domain_end": {
            "semantic_type": "viz.scale.domain",
            "token_mapping": "tokenMap(viz.scale.domain)",
            "ui_hints": {
              "component": "TimestampPreview"
            }
          },
          "viz_scale_temporal_nice": {
            "semantic_type": "viz.scale.nice",
            "token_mapping": "tokenMap(viz.scale.nice)",
            "ui_hints": {
              "component": "TextBadge"
            }
          }
        },
        "tokens": {
          "viz.scale.temporal.grid": "var(--cmp-viz-grid-line)",
          "viz.scale.temporal.axis": "var(--cmp-viz-axis-line)",
          "viz.scale.temporal.tick": "var(--cmp-viz-axis-tick)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-11-15",
          "updated": "2026-09-14",
          "owners": [
            "viz@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "keyboard": "Temporal scale controls are keyboard-operable in VizScaleControls form.",
            "screenreader": "Temporal axes and tooltips use UTC."
          },
          "regionsUsed": [
            "detail",
            "form"
          ],
          "allows": [
            "EncodingPositionX",
            "EncodingPositionY"
          ],
          "references": [
            "RDS.7 Trait-Driven Visualization System Specification (v0.1)"
          ]
        },
        "objects": [],
        "source": "traits/viz/scale-temporal.trait.yaml"
      },
      "ScatterPlot": {
        "name": "ScatterPlot",
        "version": "0.1.0",
        "description": "Scatter authoring over the existing MarkPoint renderer",
        "category": "viz.pattern",
        "tags": [
          "viz",
          "authoring"
        ],
        "contexts": [
          "detail",
          "form"
        ],
        "viewExtensions": [
          {
            "component": "VizScatterControls",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "intentParameter": "renderIntent"
            }
          },
          {
            "component": "VizScatterPreview",
            "context": "detail",
            "position": "top",
            "priority": null,
            "props": {
              "svgParameter": "previewSvg"
            }
          }
        ],
        "parameters": [
          {
            "name": "renderIntent",
            "type": "string",
            "required": false,
            "default": "{}",
            "description": "JSON-encoded Cartesian viz.render input fragment; data rows are supplied by the consumer."
          },
          {
            "name": "previewSvg",
            "type": "string",
            "required": false,
            "description": "Static SVG returned by viz.render for the authored sample."
          }
        ],
        "schema": {},
        "semantics": {},
        "tokens": {},
        "dependencies": [],
        "metadata": {
          "regionsUsed": [
            "form",
            "detail"
          ]
        },
        "objects": [],
        "source": "traits/viz/scatter-plot.trait.yaml"
      },
      "Searchable": {
        "name": "Searchable",
        "version": "1.0.0",
        "description": "Adds full-text search capability to list and collection views. Searchable injects a search\ninput into the header region, wires query state to the data layer, and provides semantic\ntoken mappings for consistent search UI styling across brands.\n\nThe trait supports placeholder text customization, debounce control for performance,\nand clear-on-escape behavior. Search state is managed via the searchQuery prop, which\nthe consuming layout binds to a data filter or API parameter.",
        "category": "behavioral",
        "tags": [
          "search",
          "filtering",
          "discovery",
          "list-behavior"
        ],
        "contexts": [
          "detail",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "SearchInput",
            "context": "list",
            "position": "header",
            "priority": 10,
            "props": {
              "field": "searchQuery",
              "placeholderParameter": "placeholder",
              "debounceParameter": "debounceMs",
              "minQueryLengthParameter": "minQueryLength",
              "clearableParameter": "clearable"
            }
          },
          {
            "component": "SearchInput",
            "context": "detail",
            "position": "header",
            "priority": 10,
            "props": {
              "field": "searchQuery",
              "placeholderParameter": "placeholder",
              "clearableParameter": "clearable"
            }
          }
        ],
        "parameters": [
          {
            "name": "placeholder",
            "type": "string",
            "required": false,
            "description": "Placeholder text shown in the search input when empty.",
            "default": "Search..."
          },
          {
            "name": "debounceMs",
            "type": "number",
            "required": false,
            "description": "Debounce delay in milliseconds before the search query is emitted.\nPrevents excessive re-renders or API calls while the user is typing.\n",
            "default": 300,
            "validation": {
              "minimum": 0,
              "maximum": 2000
            }
          },
          {
            "name": "minQueryLength",
            "type": "number",
            "required": false,
            "description": "Minimum number of characters before the search triggers.\nPrevents overly broad queries on large datasets.\n",
            "default": 1,
            "validation": {
              "minimum": 0,
              "maximum": 10
            }
          },
          {
            "name": "clearable",
            "type": "boolean",
            "required": false,
            "description": "Whether the search input shows a clear button when non-empty.",
            "default": true
          }
        ],
        "schema": {
          "searchQuery": {
            "type": "string",
            "required": false,
            "description": "The current search query string entered by the user.",
            "default": "",
            "validation": {
              "maxLength": 256
            }
          },
          "searchActive": {
            "type": "boolean",
            "required": false,
            "description": "Whether the search input is currently focused or has a non-empty query.",
            "default": false
          }
        },
        "semantics": {
          "searchQuery": {
            "semantic_type": "input.search.query",
            "token_mapping": "tokenMap(search.input.*)",
            "ui_hints": {
              "component": "SearchInput",
              "placeholderParameter": "placeholder",
              "debounceParameter": "debounceMs"
            }
          },
          "searchActive": {
            "semantic_type": "state.search.active",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "SearchInput",
              "description": "Drives visual active/inactive state of the search region."
            }
          }
        },
        "tokens": {
          "search.input.bg": "var(--sys-surface-default)",
          "search.input.text": "var(--sys-text-primary)",
          "search.input.placeholder": "var(--sys-text-subtle)",
          "search.input.border": "var(--sys-border-default)",
          "search.input.focus.border": "var(--sys-border-focus)",
          "search.input.focus.ring": "var(--sys-focus-ring)",
          "search.input.icon": "var(--sys-icon-subtle)",
          "search.input.clear.hover": "var(--sys-surface-hover)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2026-03-05",
          "updated": "2026-03-05",
          "owners": [
            "design@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "SearchInput supports full keyboard navigation:\n- Type to enter search query\n- Escape to clear the search input\n- Tab to move focus out of the search input\n",
            "screenreader": "Search input is labelled with role=\"search\" and an accessible name.\nCurrent query state is announced via aria-live region on debounce completion.\nClear button is announced as \"Clear search\".\n"
          },
          "regionsUsed": [
            "list",
            "detail"
          ],
          "examples": [
            "Product catalog search",
            "User directory search",
            "Knowledge base search"
          ],
          "references": [
            "Trait Engine Spec v0.1 section 2"
          ]
        },
        "objects": [
          "Product"
        ],
        "source": "traits/behavioral/Searchable.trait.yaml"
      },
      "Sortable": {
        "name": "Sortable",
        "version": "1.0.0",
        "description": "Adds column sorting controls to list and table views. Sortable injects sort indicators\ninto the header region near column headers, wires sort state to the data layer, and\nprovides semantic token mappings for consistent sort UI styling across brands.\n\nThe trait supports single-column sorting with ascending/descending/none cycle.\nSort state is managed via sortField and sortDirection props, which the consuming layout\nbinds to data ordering parameters or API sort queries.",
        "category": "behavioral",
        "tags": [
          "sorting",
          "list-behavior",
          "table",
          "ordering"
        ],
        "contexts": [
          "list"
        ],
        "viewExtensions": [
          {
            "component": "SortIndicator",
            "context": "list",
            "position": "header",
            "priority": 8,
            "props": {
              "sortFieldProp": "sortField",
              "sortDirectionProp": "sortDirection",
              "sortableFieldsParameter": "sortableFields",
              "triStateSortParameter": "triStateSort",
              "defaultSortFieldParameter": "defaultSortField",
              "defaultSortDirectionParameter": "defaultSortDirection"
            }
          }
        ],
        "parameters": [
          {
            "name": "defaultSortField",
            "type": "string",
            "required": false,
            "description": "The field name to sort by on initial load. Empty means no default sort.",
            "default": ""
          },
          {
            "name": "defaultSortDirection",
            "type": "string",
            "required": false,
            "description": "Default sort direction on initial load.",
            "default": "asc",
            "validation": {
              "enum": [
                "asc",
                "desc"
              ]
            }
          },
          {
            "name": "sortableFields",
            "type": "string[]",
            "required": false,
            "description": "List of field names that support sorting. When empty, all fields in the schema are\nconsidered sortable. When specified, only these fields show sort controls in the header.\n",
            "default": [],
            "validation": {
              "uniqueItems": true
            }
          },
          {
            "name": "triStateSort",
            "type": "boolean",
            "required": false,
            "description": "When true, sort cycles through ascending → descending → none (unsorted).\nWhen false, sort toggles between ascending and descending only.\n",
            "default": true
          }
        ],
        "schema": {
          "sortField": {
            "type": "string",
            "required": false,
            "description": "The currently active sort field name. Empty string means no active sort.",
            "default": ""
          },
          "sortDirection": {
            "type": "string",
            "required": false,
            "description": "Current sort direction.",
            "default": "asc",
            "validation": {
              "enum": [
                "asc",
                "desc"
              ]
            }
          },
          "sortActive": {
            "type": "boolean",
            "required": false,
            "description": "Whether sorting is currently applied (sortField is non-empty).",
            "default": false
          }
        },
        "semantics": {
          "sortField": {
            "semantic_type": "state.sort.field",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "SortIndicator",
              "defaultParameter": "defaultSortField"
            }
          },
          "sortDirection": {
            "semantic_type": "state.sort.direction",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "SortIndicator",
              "defaultParameter": "defaultSortDirection"
            }
          },
          "sortActive": {
            "semantic_type": "state.sort.active",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "SortIndicator",
              "description": "Drives visual highlight of the sorted column header."
            }
          }
        },
        "tokens": {
          "sort.indicator.idle": "var(--sys-icon-subtle)",
          "sort.indicator.active": "var(--sys-icon-primary)",
          "sort.indicator.hover": "var(--sys-icon-hover)",
          "sort.header.hover.bg": "var(--sys-surface-hover)",
          "sort.header.active.bg": "var(--sys-surface-accent-subtle)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2026-03-05",
          "updated": "2026-03-05",
          "owners": [
            "design@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "Sort controls are activated via column header buttons:\n- Enter/Space to cycle sort direction on the focused column\n- Tab to move between sortable column headers\n- Sort state change is announced immediately\n",
            "screenreader": "Sortable column headers use button role with aria-sort attribute\n(ascending, descending, or none). On activation, the new sort state\nis announced via aria-live region (e.g., \"Sorted by Name, ascending\").\nNon-sortable columns do not have interactive sort controls.\n"
          },
          "regionsUsed": [
            "list"
          ],
          "examples": [
            "Product catalog column sorting",
            "User directory sorting",
            "Invoice list sorting"
          ],
          "references": [
            "Trait Engine Spec v0.1 section 2"
          ]
        },
        "objects": [],
        "source": "traits/behavioral/Sortable.trait.yaml"
      },
      "Stateful": {
        "name": "Stateful",
        "version": "2.0.0",
        "description": "Normalizes lifecycle state transitions, exposes canonical status semantics, and provides\noptional transition governance for production workflows. Many objects compose Stateful\n(User, Subscription and Product among them), and it serves as the data source for the\nColorized visual trait.\n\nAt its simplest, Stateful defines an ordered list of valid states and tracks the current\nstatus. When governance is enabled via transitionRules, it additionally enforces which\ntransitions are allowed, records the actor and reason for each transition, and materializes\nthe set of valid next states — making it suitable for auditable workflows where arbitrary\nstate jumps are not permitted.",
        "category": "lifecycle",
        "tags": [
          "lifecycle",
          "status",
          "workflow",
          "state",
          "governance",
          "audit"
        ],
        "contexts": [
          "card",
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "StatusBadge",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "field": "status",
              "tone": "lifecycle"
            }
          },
          {
            "component": "StatusTimeline",
            "context": "detail",
            "position": "top",
            "priority": 40,
            "props": {
              "field": "status",
              "historyField": "state_history",
              "statesParameter": "states",
              "showActorId": true,
              "showReason": true
            }
          },
          {
            "component": "StatusSelector",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "field": "status",
              "optionsParameter": "states",
              "initialParameter": "initialState",
              "allowedTransitionsField": "allowed_transitions",
              "requireReasonParameter": "requireTransitionReason"
            }
          },
          {
            "component": "StatusBadge",
            "context": "card",
            "position": "before",
            "priority": null,
            "props": {
              "field": "status",
              "variant": "subtle"
            }
          }
        ],
        "parameters": [
          {
            "name": "states",
            "type": "string[]",
            "required": true,
            "description": "Ordered list of valid lifecycle states exposed to consumers. The order is semantic —\nit represents the typical forward progression (e.g., draft → active → archived).\nAll status values must be one of these states.\n",
            "default": [
              "draft",
              "active",
              "paused",
              "archived"
            ]
          },
          {
            "name": "initialState",
            "type": "string",
            "required": true,
            "description": "State assigned when an entity is created. Must be a member of the states parameter.\nTypically the first entry in the states list (e.g., \"draft\").\n",
            "default": "draft",
            "validation": {
              "enumFromParameter": "states"
            }
          },
          {
            "name": "transitionRules",
            "type": "Record<string, string[]>",
            "required": false,
            "description": "Allowed state transition map. Keys are source states; values are arrays of permitted\ntarget states. When provided, the system enforces that only declared transitions are\nvalid — any other transition is rejected. When omitted, all transitions between any\ntwo states in the states parameter are allowed (open model).\n\nExample for a subscription lifecycle:\n  draft: [active, archived]\n  active: [paused, archived]\n  paused: [active, archived]\n  archived: []\n",
            "default": null
          },
          {
            "name": "requireTransitionReason",
            "type": "boolean",
            "required": false,
            "description": "When true, every state transition must include a human-readable reason in the\nstate_history entry. Enforced at the application layer — transitions without a\nreason field are rejected. Useful for compliance and audit trails.\n",
            "default": false
          }
        ],
        "schema": {
          "status": {
            "type": "string",
            "required": true,
            "description": "Canonical lifecycle state derived from the states parameter. This is the single source\nof truth for the entity's current lifecycle position. Consumed by Colorized to resolve\nvisual tokens, and by view extensions to render StatusBadge and StatusTimeline.\n",
            "validation": {
              "enumFromParameter": "states"
            }
          },
          "state_history": {
            "type": "StateTransition[]",
            "required": false,
            "description": "Chronological log of state transitions. Each entry records the before/after states,\ntimestamp, and (when governance is enabled) the actor, reason, and transition metadata.\nRendered by StatusTimeline in the detail and timeline views.\n\nEntry structure:\n  - from: string (previous state)\n  - to: string (new state)\n  - timestamp: ISO 8601 datetime\n  - actor_id: string (user/system who triggered the transition, optional)\n  - reason: string (human-readable justification, required when requireTransitionReason is true)\n  - transition_metadata: Record<string, unknown> (arbitrary context, optional)\n",
            "default": []
          },
          "allowed_transitions": {
            "type": "string[]",
            "required": false,
            "description": "Materialized list of valid next states from the current status, computed from the\ntransitionRules parameter. When transitionRules is null (open model), this contains\nall states except the current one. Used by StatusSelector to disable invalid options\nand by StatusBadge to indicate available paths.\n",
            "default": []
          }
        },
        "semantics": {
          "status": {
            "semantic_type": "status.state",
            "token_mapping": "tokenMap(status.state.*)",
            "ui_hints": {
              "component": "StatusBadge",
              "showIcon": true
            }
          },
          "state_history": {
            "semantic_type": "timeline.state_transition",
            "token_mapping": "tokenMap(timeline.status.*)",
            "ui_hints": {
              "component": "StatusTimeline",
              "collapseWhenEmpty": true
            }
          },
          "allowed_transitions": {
            "semantic_type": "status.navigation",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "StatusSelector",
              "description": "Drives the set of enabled options in the state transition UI."
            }
          }
        },
        "tokens": {
          "status.state.default.bg": "var(--status-neutral-bg)",
          "status.state.default.text": "var(--status-neutral-text)",
          "status.timeline.connector": "var(--border-subtle)",
          "status.timeline.node.bg": "var(--sys-surface-raised)",
          "status.timeline.node.border": "var(--sys-border-default)",
          "status.timeline.actor.text": "var(--sys-text-secondary)",
          "status.timeline.reason.text": "var(--sys-text-tertiary)",
          "status.timeline.reason.bg": "var(--sys-surface-neutral)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-10-12",
          "updated": "2026-02-28",
          "owners": [
            "design@oods.systems",
            "engineering@oods.systems"
          ],
          "maturity": "stable",
          "composedBy": {
            "count": 18,
            "notable": [
              "User",
              "Subscription",
              "Product",
              "Order",
              "Organization",
              "Article"
            ]
          },
          "accessibility": {
            "keyboard": "StatusSelector is keyboard-navigable (arrow keys to cycle states, Enter to confirm).\nDisabled states (not in allowed_transitions) are skipped during keyboard navigation.\n",
            "screenreader": "StatusBadge announces the current state and, when allowed_transitions is populated,\nthe number of available next states (e.g., \"Status: Active. 2 transitions available.\").\nStateTransitionEvent entries announce from-state, to-state, actor, and reason.\n"
          },
          "regionsUsed": [
            "list",
            "detail",
            "form",
            "card"
          ],
          "examples": [
            "Subscription",
            "Project Workflow",
            "Order",
            "User",
            "Invoice"
          ],
          "governanceExamples": [
            {
              "name": "Subscription lifecycle",
              "transitionRules": {
                "future": [
                  "trialing",
                  "active",
                  "terminated"
                ],
                "trialing": [
                  "active",
                  "terminated"
                ],
                "active": [
                  "paused",
                  "pending_cancellation",
                  "past_due",
                  "terminated"
                ],
                "paused": [
                  "active",
                  "terminated"
                ],
                "pending_cancellation": [
                  "active",
                  "terminated"
                ],
                "past_due": [
                  "active",
                  "unpaid",
                  "terminated"
                ],
                "unpaid": [
                  "terminated"
                ],
                "terminated": []
              },
              "requireTransitionReason": true
            },
            {
              "name": "Content publishing",
              "transitionRules": {
                "draft": [
                  "review"
                ],
                "review": [
                  "draft",
                  "published"
                ],
                "published": [
                  "archived"
                ],
                "archived": [
                  "draft"
                ]
              },
              "requireTransitionReason": false
            }
          ],
          "references": [
            "Trait Engine Spec v0.1 section 2",
            "objects/provenance.v1.json#/references/ref-ca663a7c5731 — tone resolution for Colorized integration",
            "objects/provenance.v1.json#/references/ref-be33a98177f7 — domain status mapping"
          ]
        },
        "objects": [
          "Article",
          "Media",
          "Organization",
          "Product",
          "Relationship",
          "Subscription",
          "Transaction",
          "User"
        ],
        "source": "traits/lifecycle/Stateful.trait.yaml"
      },
      "Statusable": {
        "name": "Statusable",
        "version": "1.0.0",
        "description": "Semantic status presentation layer that maps business statuses to visual tones,\ndesign tokens, and badge/banner rendering. Statusable owns the status registry\npattern: a domain-scoped lookup table that translates raw status strings into\nconsistent visual output (tone, label, icon, token sets).\n\nDISTINCT from Stateful — Stateful governs state machine transitions and guards;\nStatusable governs how status LOOKS. Statusable is the bridge between data-layer\nstate and the component layer (Badge, Banner, StatusBadge).\n\nCore concepts:\n- Status Registry: Map<domain, Map<status, StatusPresentation>>\n- Tone System: Six semantic tones (neutral, info, accent, success, warning, critical)\n- Token Resolution: --cmp-status-{tone}-{surface|border|text} CSS variables\n- Domain Scoping: Each domain (subscription, invoice, ticket, etc.) has its own status map\n- Emphasis Variants: badge.subtle / badge.solid, banner.subtle / banner.solid",
        "category": "visual",
        "tags": [
          "status",
          "presentation",
          "registry",
          "badge",
          "banner",
          "tone",
          "semantic",
          "saas"
        ],
        "contexts": [
          "detail",
          "form",
          "list",
          "timeline"
        ],
        "viewExtensions": [
          {
            "component": "StatusBadge",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "statusField": "status",
              "domainField": "domain",
              "emphasis": "subtle",
              "showIcon": true
            }
          },
          {
            "component": "StatusBadge",
            "context": "detail",
            "position": "main",
            "priority": 80,
            "props": {
              "statusField": "status",
              "domainField": "domain",
              "emphasis": "subtle",
              "showIcon": true
            }
          },
          {
            "component": "Banner",
            "context": "detail",
            "position": "top",
            "priority": 90,
            "props": {
              "statusField": "status",
              "domainField": "domain",
              "emphasis": "subtle",
              "showIcon": true
            }
          },
          {
            "component": "StatusBadge",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "statusField": "status",
              "domainField": "domain",
              "emphasis": "subtle",
              "readOnly": true
            }
          },
          {
            "component": "StatusBadge",
            "context": "timeline",
            "position": null,
            "priority": null,
            "props": {
              "statusField": "status",
              "domainField": "domain",
              "emphasis": "subtle",
              "showIcon": true,
              "compact": true
            }
          }
        ],
        "parameters": [
          {
            "name": "domains",
            "type": "string[]",
            "required": true,
            "description": "Domain identifiers whose statuses this object participates in.\nEach domain resolves to a scoped status map in the registry\n(e.g., \"subscription\", \"invoice\", \"ticket\", \"user\").\n",
            "default": [
              "subscription"
            ]
          },
          {
            "name": "toneAliases",
            "type": "Record<string, StatusTone>",
            "required": false,
            "description": "Custom alias map for inferring tones from token path segments.\nMerged with built-in aliases (info, positive→success, danger→critical, etc.).\nKeys are token path segments; values are canonical StatusTone values.\n",
            "default": {}
          },
          {
            "name": "defaultTone",
            "type": "StatusTone",
            "required": false,
            "description": "Fallback tone applied when a status is not found in the registry\nor when tone inference from token paths yields no match.\n",
            "default": "neutral",
            "validation": {
              "enum": [
                "neutral",
                "info",
                "accent",
                "success",
                "warning",
                "critical"
              ]
            }
          }
        ],
        "schema": {
          "status": {
            "type": "string",
            "required": true,
            "description": "Raw business status string (e.g., \"active\", \"past_due\", \"unpaid\").\nResolved against the domain's status map to derive presentation data.\n"
          },
          "domain": {
            "type": "StatusDomain",
            "required": true,
            "description": "Domain scope for registry lookup. Determines which status map is consulted\n(e.g., \"subscription\" statuses differ from \"invoice\" statuses).\n",
            "validation": {
              "enumFromParameter": "domains"
            }
          },
          "tone": {
            "type": "StatusTone",
            "required": false,
            "description": "Semantic tone derived from the registry or inferred from token paths.\nOne of: neutral, info, accent, success, warning, critical.\nFalls back to the defaultTone parameter when unresolvable.\n",
            "validation": {
              "enum": [
                "neutral",
                "info",
                "accent",
                "success",
                "warning",
                "critical"
              ]
            }
          },
          "badge_tokens": {
            "type": "StatusTokenVariants",
            "required": false,
            "description": "Resolved badge token sets with subtle and solid emphasis variants.\nEach variant contains { background, border, foreground } CSS variable references.\nStructure: { subtle: StatusTokenSet, solid: StatusTokenSet }\n"
          },
          "banner_tokens": {
            "type": "StatusTokenVariants",
            "required": false,
            "description": "Resolved banner token sets with subtle and solid emphasis variants.\nSubtle banners use domain-specific tokens when available; solid banners\nuse the tone-based component token set.\nStructure: { subtle: StatusTokenSet, solid: StatusTokenSet }\n"
          }
        },
        "semantics": {
          "status": {
            "semantic_type": "status.presentation.status",
            "token_mapping": "tokenMap(status.registry.*)",
            "ui_hints": {
              "component": "StatusBadge",
              "registryLookup": "getStatusPresentation(domain, status)"
            }
          },
          "domain": {
            "semantic_type": "status.presentation.domain",
            "token_mapping": "tokenMap(status.domains.*)",
            "ui_hints": {
              "component": "DomainSelector",
              "scopedTo": "domains"
            }
          },
          "tone": {
            "semantic_type": "status.presentation.tone",
            "token_mapping": "tokenMap(status.tone.*)",
            "ui_hints": {
              "component": "ToneBadge",
              "toneValues": [
                "neutral",
                "info",
                "accent",
                "success",
                "warning",
                "critical"
              ]
            }
          },
          "badge_tokens": {
            "semantic_type": "status.presentation.badge",
            "token_mapping": "tokenMap(cmp.status.{tone}.*)",
            "ui_hints": {
              "component": "Badge",
              "emphasisVariants": [
                "subtle",
                "solid"
              ]
            }
          },
          "banner_tokens": {
            "semantic_type": "status.presentation.banner",
            "token_mapping": "tokenMap(cmp.status.{tone}.*)",
            "ui_hints": {
              "component": "Banner",
              "emphasisVariants": [
                "subtle",
                "solid"
              ]
            }
          }
        },
        "tokens": {
          "cmp.status.neutral.surface": "var(--sys-surface-neutral)",
          "cmp.status.neutral.border": "var(--sys-border-neutral)",
          "cmp.status.neutral.text": "var(--sys-text-neutral)",
          "cmp.status.info.surface": "var(--sys-surface-info)",
          "cmp.status.info.border": "var(--sys-border-info)",
          "cmp.status.info.text": "var(--sys-text-info)",
          "cmp.status.accent.surface": "var(--sys-surface-accent)",
          "cmp.status.accent.border": "var(--sys-border-accent)",
          "cmp.status.accent.text": "var(--sys-text-accent)",
          "cmp.status.success.surface": "var(--sys-surface-success)",
          "cmp.status.success.border": "var(--sys-border-success)",
          "cmp.status.success.text": "var(--sys-text-success)",
          "cmp.status.warning.surface": "var(--sys-surface-warning)",
          "cmp.status.warning.border": "var(--sys-border-warning)",
          "cmp.status.warning.text": "var(--sys-text-warning)",
          "cmp.status.critical.surface": "var(--sys-surface-critical)",
          "cmp.status.critical.border": "var(--sys-border-critical)",
          "cmp.status.critical.text": "var(--sys-text-critical)",
          "cmp.banner.background": "var(--sys-surface-raised)",
          "cmp.banner.border": "var(--sys-border-default)",
          "cmp.banner.text": "var(--sys-text-default)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2026-02-28",
          "owners": [
            "design@oods.systems",
            "engineering@oods.systems"
          ],
          "maturity": "experimental",
          "accessibility": {
            "keyboard": "Badge and Banner elements are not interactive; no keyboard handling required.",
            "screenreader": "StatusBadge announces status label and tone as a live region.\nBanner uses role=\"status\" with aria-live=\"polite\" for critical/warning tones.\n"
          },
          "regionsUsed": [
            "list",
            "detail",
            "form",
            "timeline"
          ],
          "examples": [
            "Subscription",
            "Invoice",
            "Ticket",
            "User"
          ],
          "references": [
            "objects/provenance.v1.json#/references/ref-ca663a7c5731 — StatusPresentation, StatusTone, tone inference, domain maps",
            "objects/provenance.v1.json#/references/ref-24923e661958 — 7 sub-stories across 5 domains",
            "objects/provenance.v1.json#/references/ref-be33a98177f7 — domain status token map consumed by registry",
            "objects/provenance.v1.json#/references/ref-c373015a9045 — StatusableViewData, StatusTransitionEvent interfaces",
            "objects/provenance.v1.json#/references/ref-cc4cadcf82d5 — formatStatus, resolveDisplayName utilities"
          ]
        },
        "objects": [],
        "source": "traits/visual/Statusable.trait.yaml"
      },
      "Supersedable": {
        "name": "Supersedable",
        "version": "1.0.0",
        "description": "Records that one record replaces another of the same kind, and which of them still stands.\n\nSupersession is a self-referencing lineage, not a workflow: a record does not move through\nsupersession, it is replaced by a later record, and the pair stays readable afterwards. That is\nwhy it is its own trait rather than a Stateful state set — Stateful governs transitions between\nstates of one record, while Supersedable relates two records and keeps both.\n\nTwo stores already hold that shape and they record it from opposite ends. A decision store writes\nthe forward pointer (`superseded_by`, the replacement's id) beside a status of\nactive | superseded | archived | stale. OODS Foundry's own composition acceptances write the\nbackward pointer (`supersedes`, the acceptance this one replaced, with the time it was accepted)\nand leave the standing acceptance implicit. The trait therefore declares both pointers and a\n`recordedDirection` parameter naming which one the source of truth actually writes; the other is\nderived where the store can derive it and left absent where it cannot. An absent pointer means\nunknown, never \"nothing was superseded\".\n\nThe field is `supersession_status`, not `status`, so an object can carry its own lifecycle\nthrough Stateful and its supersession through this trait without the two colliding.",
        "category": "lifecycle",
        "tags": [
          "lifecycle",
          "supersession",
          "lineage",
          "provenance",
          "versioning"
        ],
        "contexts": [
          "card",
          "detail",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "StatusBadge",
            "context": "list",
            "position": "after",
            "priority": null,
            "props": {
              "statusField": "supersession_status",
              "emphasis": "subtle",
              "showIcon": false
            }
          },
          {
            "component": "StatusBadge",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "statusField": "supersession_status",
              "emphasis": "subtle",
              "showIcon": false
            }
          },
          {
            "component": "StatusBadge",
            "context": "detail",
            "position": "main",
            "priority": 70,
            "props": {
              "statusField": "supersession_status",
              "emphasis": "subtle",
              "showIcon": false
            }
          },
          {
            "component": "Text",
            "context": "detail",
            "position": "main",
            "priority": 69,
            "props": {
              "field": "superseded_by"
            }
          },
          {
            "component": "Text",
            "context": "detail",
            "position": "main",
            "priority": 68,
            "props": {
              "field": "supersedes"
            }
          },
          {
            "component": "Text",
            "context": "detail",
            "position": "main",
            "priority": 67,
            "props": {
              "field": "supersession_reason"
            }
          }
        ],
        "parameters": [
          {
            "name": "states",
            "type": "string[]",
            "required": true,
            "description": "The supersession states this store can actually write. A store that only ever distinguishes a\nstanding record from a replaced one declares two; a decision store declares four because it also\nretires a decision without replacing it (archived) and marks one as needing review (stale).\n",
            "default": [
              "active",
              "superseded",
              "archived",
              "stale"
            ]
          },
          {
            "name": "initialState",
            "type": "string",
            "required": true,
            "description": "The state a newly recorded entry holds before anything replaces it.",
            "default": "active",
            "validation": {
              "enumFromParameter": "states"
            }
          },
          {
            "name": "recordedDirection",
            "type": "string",
            "required": true,
            "description": "Which pointer the source of truth writes: `forward` stores `superseded_by` on the record that\nwas replaced (a decision store), `backward` stores `supersedes` on the record that replaced it (OODS Foundry's\ncomposition acceptances), `both` stores each. The pointer that is not recorded is derived only\nwhen the store can derive it, and is otherwise absent — the screen says unknown rather than\nclaiming the record supersedes nothing.\n",
            "default": "forward",
            "validation": {
              "enum": [
                "forward",
                "backward",
                "both"
              ]
            }
          },
          {
            "name": "supersededLabel",
            "type": "string",
            "required": false,
            "description": "Visible wording for a record that has been replaced, so the screen never relies on colour alone.",
            "default": "Superseded"
          }
        ],
        "schema": {
          "supersession_status": {
            "type": "string",
            "required": true,
            "default": "active",
            "description": "Whether this record still stands. Named apart from Stateful's `status` so an object can carry\nboth a lifecycle and a supersession lineage.\n"
          },
          "superseded_by": {
            "type": "string",
            "required": false,
            "description": "Identifier of the record that replaced this one. Present when the store records the forward\npointer. Absent means not replaced, or not known — the two are distinguished by\nsupersession_status, never by the pointer alone.\n"
          },
          "supersedes": {
            "type": "string",
            "required": false,
            "description": "Identifier of the record this one replaced. Present when the store records the backward\npointer. Never inferred from ordering.\n"
          },
          "superseded_at": {
            "type": "datetime?",
            "required": false,
            "description": "When the replacement happened, when the store records it. A store that does not record it leaves\nit absent rather than borrowing the replacement's creation time.\n"
          },
          "supersession_reason": {
            "type": "string",
            "required": false,
            "description": "Why the record was replaced, when the store carries a reason.",
            "validation": {
              "maxLength": 500
            }
          }
        },
        "semantics": {
          "supersession_status": {
            "semantic_type": "lifecycle.supersession.state",
            "token_mapping": "tokenMap(lifecycle.supersession.*)",
            "ui_hints": {
              "component": "StatusBadge",
              "showIcon": false
            }
          },
          "superseded_by": {
            "semantic_type": "lifecycle.supersession.replacement",
            "token_mapping": "tokenMap(lifecycle.supersession.link)",
            "ui_hints": {
              "component": "Text"
            }
          },
          "supersedes": {
            "semantic_type": "lifecycle.supersession.replaced",
            "token_mapping": "tokenMap(lifecycle.supersession.link)",
            "ui_hints": {
              "component": "Text"
            }
          },
          "superseded_at": {
            "semantic_type": "lifecycle.supersession.timestamp",
            "token_mapping": "tokenMap(lifecycle.supersession.timestamp)",
            "ui_hints": {
              "component": "RelativeTimestamp"
            }
          },
          "supersession_reason": {
            "semantic_type": "lifecycle.supersession.reason",
            "token_mapping": "tokenMap(lifecycle.supersession.reason)",
            "ui_hints": {
              "component": "Text",
              "maxLength": 500
            }
          }
        },
        "tokens": {
          "lifecycle.supersession.active.bg": "var(--sys-status-success-surface)",
          "lifecycle.supersession.active.text": "var(--sys-status-success-text)",
          "lifecycle.supersession.superseded.bg": "var(--sys-surface-neutral)",
          "lifecycle.supersession.superseded.text": "var(--sys-text-secondary)",
          "lifecycle.supersession.link.text": "var(--text-strong)",
          "lifecycle.supersession.timestamp.text": "var(--text-subtle)",
          "lifecycle.supersession.reason.text": "var(--text-default)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2026-09-16",
          "updated": "2026-09-16",
          "owners": [
            "lifecycle@oods.systems"
          ],
          "maturity": "alpha",
          "accessibility": {
            "keyboard": "Supersession adds no interactive control of its own; the pointer renders as text beside the\nrecord it names.\n",
            "screenreader": "The supersession state is announced as visible text through StatusBadge, not by colour alone, and\nthe pointer fields read as \"Superseded by <id>\" / \"Supersedes <id>\".\n"
          },
          "regionsUsed": [
            "list",
            "card",
            "detail"
          ],
          "examples": [
            "Decision"
          ],
          "references": [
            "objects/provenance.v1.json#/references/ref-d6670b6a0f62 — CompositionAcceptance.supersedes, the backward-recording consumer",
            "A CMOS store's strategic_decisions.superseded_by + status, the forward-recording consumer"
          ]
        },
        "objects": [],
        "source": "traits/lifecycle/Supersedable.trait.yaml"
      },
      "Taggable": {
        "name": "Taggable",
        "version": "2.0.0",
        "description": "Adds configurable tag management with guardrails for custom authoring, taxonomy alignment,\nand tag governance. Taggable supports both open tagging (user-defined) and controlled\nvocabularies (allow-list), with optional moderation workflows for tag quality control.\n\nTags are first-class metadata in OODS — they drive discovery, filtering, and cross-object\nrelationships. The trait provides per-tag governance metadata (creator, creation date,\nusage count) for taxonomy health monitoring, and optional synonym resolution to prevent\ntag fragmentation (e.g., \"javascript\" and \"js\" resolve to the same canonical tag).",
        "category": "behavioral",
        "tags": [
          "tagging",
          "classification",
          "metadata",
          "discovery",
          "governance",
          "taxonomy"
        ],
        "contexts": [
          "card",
          "detail",
          "form",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "TagPills",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "field": "tags",
              "maxVisible": 3,
              "overflowLabel": "+{{ tag_count }}"
            }
          },
          {
            "component": "TagSummary",
            "context": "detail",
            "position": "top",
            "priority": null,
            "props": {
              "field": "tags",
              "countField": "tag_count"
            }
          },
          {
            "component": "TagInput",
            "context": "form",
            "position": "top",
            "priority": null,
            "props": {
              "field": "tags",
              "maxTagsParameter": "maxTags",
              "allowCustomParameter": "allowCustomTags",
              "allowListParameter": "allowedTags",
              "minLengthParameter": "tagMinLength",
              "maxLengthParameter": "tagMaxLength",
              "synonymParameter": "synonymResolution"
            }
          },
          {
            "component": "TagPills",
            "context": "card",
            "position": "after",
            "priority": null,
            "props": {
              "field": "tags",
              "maxVisible": 3,
              "overflowLabel": "+{{ tag_count }}"
            }
          }
        ],
        "parameters": [
          {
            "name": "maxTags",
            "type": "number",
            "required": false,
            "description": "Maximum number of tags that can be attached to an entity.",
            "default": 10,
            "validation": {
              "minimum": 1,
              "maximum": 64
            }
          },
          {
            "name": "allowCustomTags",
            "type": "boolean",
            "required": false,
            "description": "Whether editors may author tags outside of the approved allow list. When false,\nonly tags from allowedTags are permitted. When true with allowedTags present,\nthe allow list serves as suggestions rather than a constraint.\n",
            "default": true
          },
          {
            "name": "allowedTags",
            "type": "string[]",
            "required": false,
            "description": "Curated allow list of permitted tags. Behavior depends on allowCustomTags:\n- allowCustomTags=false: Only these tags are permitted (strict mode).\n- allowCustomTags=true: These tags appear as suggestions in TagInput autocomplete.\n",
            "validation": {
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "minLength": 1,
                "maxLength": 64
              }
            }
          },
          {
            "name": "caseSensitive",
            "type": "boolean",
            "required": false,
            "description": "Whether tag comparisons should treat casing as significant.",
            "default": false
          },
          {
            "name": "tagMinLength",
            "type": "number",
            "required": false,
            "description": "Minimum character length for a tag value. Prevents single-character or empty tags\nthat add noise to the taxonomy. Applied to both custom and allow-list tags.\n",
            "default": 2,
            "validation": {
              "minimum": 1,
              "maximum": 32
            }
          },
          {
            "name": "tagMaxLength",
            "type": "number",
            "required": false,
            "description": "Maximum character length for a tag value. Prevents excessively long tags that\nbreak UI layouts and reduce readability.\n",
            "default": 64,
            "validation": {
              "minimum": 1,
              "maximum": 256
            }
          },
          {
            "name": "allowTagModeration",
            "type": "boolean",
            "required": false,
            "description": "When true, newly created custom tags enter a \"pending\" state and require approval\nfrom a moderator before becoming visible to other users. Tags from the allowedTags\nlist are pre-approved and skip moderation. Useful for public-facing taxonomies where\ntag quality matters.\n",
            "default": false
          },
          {
            "name": "synonymResolution",
            "type": "string",
            "required": false,
            "description": "Controls how synonym/alias tags are handled:\n- none: No synonym resolution. Tags are stored as-is.\n- suggest: When a tag matches a known synonym, the UI suggests the canonical form\n  but allows the original.\n- auto: Tags matching known synonyms are automatically replaced with the canonical\n  form on save. Requires a synonym map in tag_metadata.\n",
            "default": "none",
            "validation": {
              "enum": [
                "none",
                "suggest",
                "auto"
              ]
            }
          }
        ],
        "schema": {
          "tags": {
            "type": "string[]",
            "required": false,
            "description": "Ordered list of tags assigned to the entity.",
            "default": [],
            "validation": {
              "maxItems": 64
            }
          },
          "tag_count": {
            "type": "number",
            "required": true,
            "description": "Computed number of tags assigned to the entity.",
            "default": 0,
            "validation": {
              "minimum": 0
            }
          },
          "tag_metadata": {
            "type": "object[]",
            "required": false,
            "description": "Per-tag governance metadata. Each entry corresponds to a tag in the tags array and\ntracks provenance and usage for taxonomy health monitoring.\n\nEntry structure:\n  - tag: string (the tag value, matches entry in tags array)\n  - created_at: ISO 8601 datetime\n  - created_by: string (user ID or \"system\" for allow-list tags)\n  - usage_count: number (how many entities use this tag, computed)\n  - moderation_status: \"approved\" | \"pending\" | \"rejected\" (when allowTagModeration is true)\n  - canonical_form: string (resolved synonym target, when synonymResolution is enabled)\n",
            "default": []
          }
        },
        "semantics": {
          "tags": {
            "semantic_type": "taxonomy.tag.collection",
            "token_mapping": "tokenMap(taxonomy.tag.*)",
            "ui_hints": {
              "component": "TagCollection",
              "allowCreateParameter": "allowCustomTags",
              "allowListParameter": "allowedTags",
              "caseSensitiveParameter": "caseSensitive"
            }
          },
          "tag_count": {
            "semantic_type": "metric.collection.count",
            "token_mapping": "tokenMap(taxonomy.tag.count)",
            "ui_hints": {
              "component": "MetricBadge",
              "format": "integer"
            }
          },
          "tag_metadata": {
            "semantic_type": "taxonomy.tag.governance",
            "token_mapping": "computed",
            "ui_hints": {
              "component": "TagGovernancePanel",
              "description": "Admin panel for reviewing tag health, moderation queue, and synonym resolution."
            }
          }
        },
        "tokens": {
          "taxonomy.tag.chip.bg": "var(--surface-tag-bg)",
          "taxonomy.tag.chip.text": "var(--surface-tag-text)",
          "taxonomy.tag.chip.border": "var(--sys-border-default)",
          "taxonomy.tag.chip.hover.bg": "var(--sys-surface-hover)",
          "taxonomy.tag.chip.pending.bg": "var(--sys-status-warning-surface)",
          "taxonomy.tag.chip.pending.text": "var(--sys-status-warning-text)",
          "taxonomy.tag.summary.count": "var(--text-subtle)",
          "taxonomy.tag.input.border": "var(--sys-border-default)",
          "taxonomy.tag.input.focus.border": "var(--sys-border-focus)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-10-12",
          "updated": "2026-02-28",
          "owners": [
            "design@oods.systems",
            "taxonomy@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "TagInput supports full keyboard navigation:\n- Type to filter/create tags, Enter to confirm\n- Backspace to remove the last tag when input is empty\n- Arrow keys to navigate autocomplete suggestions\n- Escape to dismiss the autocomplete dropdown\n- Tab to move focus out of the tag input\nTagPills in list view are not interactive (display only).\n",
            "screenreader": "Tag list is announced as a group with count (e.g., \"Tags: 3 items\").\nEach tag chip is announced individually. When moderation is enabled,\npending tags are announced with their moderation status.\nTagInput announces available suggestion count on keystroke.\n"
          },
          "regionsUsed": [
            "list",
            "detail",
            "form",
            "card"
          ],
          "examples": [
            "Knowledge Article",
            "Incident",
            "Product",
            "Media"
          ],
          "references": [
            "Trait Engine Spec v0.1 section 2"
          ]
        },
        "objects": [
          "Organization",
          "Relationship",
          "User"
        ],
        "source": "traits/behavioral/Taggable.trait.yaml"
      },
      "Timestampable": {
        "name": "Timestampable",
        "version": "1.0.0",
        "description": "Captures creation and update timestamps with configurable audit metadata for lifecycle tracking.",
        "category": "lifecycle",
        "tags": [
          "timestamp",
          "audit",
          "lifecycle",
          "metadata"
        ],
        "contexts": [
          "detail",
          "list"
        ],
        "viewExtensions": [
          {
            "component": "AuditTimeline",
            "context": "detail",
            "position": "bottom",
            "priority": null,
            "props": {
              "createdField": "created_at",
              "updatedField": "updated_at",
              "eventField": "last_event",
              "eventTimestampField": "last_event_at",
              "eventOptionsParameter": "recordedEvents"
            }
          },
          {
            "component": "RelativeTimestamp",
            "context": "list",
            "position": null,
            "priority": null,
            "props": {
              "field": "updated_at",
              "fallbackField": "created_at",
              "timezoneParameter": "timezone"
            }
          }
        ],
        "parameters": [
          {
            "name": "recordedEvents",
            "type": "string[]",
            "required": true,
            "description": "Canonical lifecycle events captured in the audit timeline.",
            "default": [
              "created",
              "updated",
              "deleted"
            ]
          },
          {
            "name": "timezone",
            "type": "string",
            "required": false,
            "description": "Default timezone context applied when rendering timestamps.",
            "default": "UTC",
            "validation": {
              "enum": [
                "UTC",
                "LOCAL",
                "OFFSET"
              ]
            }
          },
          {
            "name": "allowNullUpdatedAt",
            "type": "boolean",
            "required": false,
            "description": "Whether updated_at may be omitted when no mutations have occurred.",
            "default": true
          }
        ],
        "schema": {
          "created_at": {
            "type": "datetime",
            "required": true,
            "description": "Timestamp recording when the entity was first created."
          },
          "updated_at": {
            "type": "datetime",
            "required": false,
            "description": "Timestamp for the most recent modification, when available."
          },
          "last_event": {
            "type": "string",
            "required": true,
            "description": "Lifecycle event associated with the most recent timestamp mutation.",
            "validation": {
              "enumFromParameter": "recordedEvents"
            }
          },
          "last_event_at": {
            "type": "datetime",
            "required": false,
            "description": "Timestamp for the lifecycle event captured in last_event."
          }
        },
        "semantics": {
          "created_at": {
            "semantic_type": "audit.created_at",
            "token_mapping": "tokenMap(audit.created)",
            "ui_hints": {
              "component": "TimelineTimestamp",
              "timezoneParameter": "timezone"
            }
          },
          "updated_at": {
            "semantic_type": "audit.updated_at",
            "token_mapping": "tokenMap(audit.updated)",
            "ui_hints": {
              "component": "TimelineTimestamp",
              "timezoneParameter": "timezone",
              "allowNullParameter": "allowNullUpdatedAt"
            }
          },
          "last_event": {
            "semantic_type": "audit.event.type",
            "token_mapping": "tokenMap(audit.event.*)",
            "ui_hints": {
              "component": "AuditBadge",
              "parameterSource": "recordedEvents"
            }
          },
          "last_event_at": {
            "semantic_type": "audit.event.timestamp",
            "token_mapping": "tokenMap(audit.event.timestamp)",
            "ui_hints": {
              "component": "TimelineTimestamp",
              "timezoneParameter": "timezone"
            }
          }
        },
        "tokens": {
          "audit.created.badge.text": "var(--text-subtle)",
          "audit.updated.badge.text": "var(--text-subtle)",
          "audit.event.badge.bg": "var(--surface-muted)"
        },
        "dependencies": [],
        "metadata": {
          "created": "2025-10-16",
          "owners": [
            "lifecycle@oods.systems",
            "platform@oods.systems"
          ],
          "maturity": "stable",
          "accessibility": {
            "keyboard": "n/a",
            "screenreader": "Announces creation and last update information with lifecycle context."
          },
          "regionsUsed": [
            "detail",
            "list"
          ],
          "examples": [
            "User",
            "Organization",
            "Transaction"
          ],
          "references": [
            "Trait Engine Spec v0.1 §2"
          ]
        },
        "objects": [
          "Article",
          "Invoice",
          "Media",
          "Organization",
          "Product",
          "Relationship",
          "Subscription",
          "Transaction",
          "Usage",
          "User"
        ],
        "source": "traits/lifecycle/Timestampable.trait.yaml"
      }
    },
    "objects": {
      "Article": {
        "name": "Article",
        "version": "1.0.0",
        "domain": "content.publication",
        "description": "Canonical editorial article with hybrid taxonomy + tag classification for CMS surfaces.",
        "tags": [
          "content",
          "article",
          "hybrid",
          "classifiable"
        ],
        "traits": [
          {
            "reference": "content/Labelled",
            "alias": "ArticleHeadline",
            "parameters": {}
          },
          {
            "reference": "lifecycle/Stateful",
            "alias": "ArticleWorkflow",
            "parameters": {
              "states": [
                "draft",
                "in_review",
                "scheduled",
                "published",
                "archived"
              ],
              "initialState": "draft"
            }
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": "ArticleTimestamps",
            "parameters": {
              "recordedEvents": [
                "created",
                "scheduled",
                "published",
                "updated",
                "archived"
              ],
              "timezone": "UTC"
            }
          },
          {
            "reference": "core/Classifiable",
            "alias": "ArticleClassification",
            "parameters": {
              "classification_mode": "hybrid",
              "hierarchy_storage_model": "materialized_path",
              "tag_policy": "moderated",
              "max_tags": 24,
              "require_primary_category": true
            }
          }
        ],
        "fields": [
          "article_id",
          "slug",
          "author_id",
          "author_name",
          "content_type",
          "excerpt",
          "body_markdown",
          "hero_media_id",
          "reading_time_minutes",
          "locale",
          "published_at"
        ],
        "semantics": {
          "description": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "TextBody",
              "maxLengthParameter": "maxDescriptionLength"
            }
          },
          "article_id": {
            "semantic_type": "content.article.id",
            "token_mapping": "tokenMap(content.article.id)"
          },
          "slug": {
            "semantic_type": "content.article.slug",
            "token_mapping": "tokenMap(content.article.slug)"
          },
          "author_id": {
            "semantic_type": "content.article.author",
            "token_mapping": "tokenMap(identity.user.id)",
            "ui_hints": {
              "displayLabelField": "author_name"
            }
          },
          "content_type": {
            "semantic_type": "content.article.type",
            "token_mapping": "tokenMap(content.article.type)"
          },
          "reading_time_minutes": {
            "semantic_type": "content.article.read_time",
            "token_mapping": "tokenMap(metric.duration.short)"
          },
          "locale": {
            "semantic_type": "content.article.locale",
            "token_mapping": "tokenMap(content.locale.badge)"
          },
          "published_at": {
            "semantic_type": "content.article.published_at",
            "token_mapping": "tokenMap(timestamp.published_at)"
          }
        },
        "tokens": {
          "content.article.id": "var(--sys-text-strong)",
          "content.article.slug": "var(--sys-text-muted)",
          "content.article.type": "var(--sys-badge-neutral-fg)",
          "content.article.read_time": "var(--sys-text-subtle)",
          "content.locale.badge": "var(--sys-badge-accent-fg)",
          "timestamp.published_at": "var(--sys-text-muted)"
        },
        "metadata": {
          "owners": [
            "content-platform@oods.systems",
            "docs@oods.systems"
          ],
          "steward": "publishing@oods.systems",
          "changelog": [
            {
              "version": "1.0.0",
              "date": "2025-11-18",
              "description": "Initial article object composing hybrid Classifiable mode for taxonomy + tags."
            }
          ]
        },
        "visibility": "public",
        "source": "objects/content/Article.object.yaml"
      },
      "Invoice": {
        "name": "Invoice",
        "version": "1.0.0",
        "domain": "saas.billing",
        "description": "Canonical SaaS invoice object normalizing payment terms, status, and refund posture.",
        "tags": [
          "billing",
          "invoice",
          "finance"
        ],
        "traits": [
          {
            "reference": "SaaSBillingPayable",
            "alias": "InvoiceTerms",
            "parameters": {}
          },
          {
            "reference": "SaaSBillingRefundable",
            "alias": "CreditWindow",
            "parameters": {}
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": "AuditTrail",
            "parameters": {
              "recordedEvents": [
                "created",
                "posted",
                "payment_initiated",
                "payment_cleared",
                "payment_failed",
                "voided",
                "written_off"
              ],
              "timezone": "UTC",
              "allowNullUpdatedAt": true
            }
          },
          {
            "reference": "viz/MarkBar",
            "alias": null,
            "parameters": {
              "title": "Invoice line item amounts",
              "description": "Line-item amounts in the invoice's currency; line items with the same description are summed.",
              "chart": {
                "chartType": "bar",
                "source": "record-array",
                "dataField": "line_items",
                "encodings": {
                  "x": {
                    "field": "description",
                    "title": "Line item"
                  },
                  "y": {
                    "field": "amount_minor",
                    "aggregate": "sum",
                    "title": "Amount"
                  }
                },
                "minorUnits": 100,
                "currencyField": "currency",
                "sampleRows": [
                  {
                    "description": "Scale plan",
                    "quantity": 1,
                    "amount_minor": 284000,
                    "unit_amount_minor": 284000
                  }
                ]
              }
            }
          }
        ],
        "fields": [
          "invoice_id",
          "subscription_id",
          "provider",
          "provider_invoice_id",
          "billing_contact_name",
          "billing_contact_email",
          "tax_minor",
          "discount_minor",
          "subtotal_minor",
          "line_items",
          "attachments",
          "portal_url",
          "dunning_step",
          "payment_source"
        ],
        "semantics": {
          "invoice_id": {
            "semantic_type": "billing.invoice.id",
            "token_mapping": "tokenMap(billing.invoice.id)"
          },
          "subscription_id": {
            "semantic_type": "billing.invoice.subscription_id",
            "token_mapping": "tokenMap(billing.invoice.subscription_id)"
          },
          "provider": {
            "semantic_type": "billing.invoice.provider",
            "token_mapping": "tokenMap(billing.invoice.provider)"
          },
          "provider_invoice_id": {
            "semantic_type": "billing.invoice.provider_id",
            "token_mapping": "tokenMap(billing.invoice.provider_id)"
          },
          "billing_contact_name": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(billing.invoice.billing_contact_name)"
          },
          "billing_contact_email": {
            "semantic_type": "billing.invoice.billing_contact_email",
            "token_mapping": "tokenMap(billing.invoice.billing_contact_email)"
          },
          "tax_minor": {
            "semantic_type": "billing.invoice.tax_minor",
            "token_mapping": "tokenMap(billing.invoice.tax_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "discount_minor": {
            "semantic_type": "billing.invoice.discount_minor",
            "token_mapping": "tokenMap(billing.invoice.discount_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "subtotal_minor": {
            "semantic_type": "billing.invoice.subtotal_minor",
            "token_mapping": "tokenMap(billing.invoice.subtotal_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "line_items": {
            "semantic_type": "billing.invoice.line_items",
            "token_mapping": "tokenMap(billing.invoice.line_items)"
          },
          "attachments": {
            "semantic_type": "billing.invoice.attachments",
            "token_mapping": "tokenMap(billing.invoice.attachments)"
          },
          "portal_url": {
            "semantic_type": "billing.invoice.portal_url",
            "token_mapping": "tokenMap(billing.invoice.portal_url)"
          },
          "dunning_step": {
            "semantic_type": "billing.invoice.dunning_step",
            "token_mapping": "tokenMap(billing.invoice.dunning_step)"
          },
          "payment_source": {
            "semantic_type": "billing.invoice.payment_source",
            "token_mapping": "tokenMap(billing.invoice.payment_source)"
          }
        },
        "tokens": {
          "billing.invoice.id": "var(--cmp-text-strong)",
          "billing.invoice.billing_contact_name": "var(--cmp-text-body-strong)",
          "billing.invoice.payment_source": "var(--cmp-text-subtle)",
          "billing.invoice.dunning_step": "var(--cmp-badge-text-warning)"
        },
        "metadata": {
          "owners": [
            "revenue-ops@oods.systems",
            "finance@oods.systems"
          ],
          "maturity": "beta",
          "references": [
            {
              "R13.5 Canonical Model": "Subscription and Invoice"
            },
            "R4.5 SaaS Enum-to-Token Mapping Schema"
          ]
        },
        "visibility": "public",
        "source": "domains/saas-billing/objects/Invoice.object.yaml"
      },
      "Media": {
        "name": "Media",
        "version": "1.0.0",
        "domain": "content.asset",
        "description": "Canonical digital asset metadata powering media library, DAM, and CMS integrations.",
        "tags": [
          "content",
          "media",
          "asset",
          "classifiable"
        ],
        "traits": [
          {
            "reference": "content/Labelled",
            "alias": "MediaLabel",
            "parameters": {}
          },
          {
            "reference": "lifecycle/Stateful",
            "alias": "MediaLifecycle",
            "parameters": {
              "states": [
                "ingested",
                "processing",
                "available",
                "deprecated"
              ],
              "initialState": "ingested"
            }
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": "MediaTimestamps",
            "parameters": {
              "recordedEvents": [
                "ingested",
                "transcoded",
                "published",
                "archived"
              ],
              "timezone": "UTC"
            }
          },
          {
            "reference": "core/Classifiable",
            "alias": "MediaClassification",
            "parameters": {
              "classification_mode": "tag",
              "tag_policy": "open",
              "max_tags": 32
            }
          }
        ],
        "fields": [
          "media_id",
          "asset_type",
          "mime_type",
          "storage_bucket",
          "object_key",
          "source_url",
          "checksum",
          "file_size_bytes",
          "width_px",
          "height_px",
          "duration_seconds",
          "transcoding_profiles"
        ],
        "semantics": {
          "description": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "TextBody",
              "maxLengthParameter": "maxDescriptionLength"
            }
          },
          "media_id": {
            "semantic_type": "media.asset.id",
            "token_mapping": "tokenMap(media.asset.id)"
          },
          "asset_type": {
            "semantic_type": "media.asset.type",
            "token_mapping": "tokenMap(media.asset.type)"
          },
          "mime_type": {
            "semantic_type": "media.asset.mime",
            "token_mapping": "tokenMap(media.asset.mime)"
          },
          "file_size_bytes": {
            "semantic_type": "media.asset.size",
            "token_mapping": "tokenMap(metric.storage.bytes)"
          },
          "duration_seconds": {
            "semantic_type": "media.asset.duration",
            "token_mapping": "tokenMap(metric.duration.media)"
          }
        },
        "tokens": {
          "media.asset.id": "var(--sys-text-strong)",
          "media.asset.type": "var(--sys-badge-neutral-fg)",
          "media.asset.mime": "var(--sys-text-muted)",
          "metric.storage.bytes": "var(--sys-text-subtle)",
          "metric.duration.media": "var(--sys-text-subtle)"
        },
        "metadata": {
          "owners": [
            "media-platform@oods.systems",
            "dam@oods.systems"
          ],
          "steward": "experience@oods.systems",
          "changelog": [
            {
              "version": "1.0.0",
              "date": "2025-11-18",
              "description": "Initial Media object with tag-mode Classifiable integration for asset folksonomy."
            }
          ]
        },
        "visibility": "public",
        "source": "objects/content/Media.object.yaml"
      },
      "Organization": {
        "name": "Organization",
        "version": "1.2.0",
        "domain": "core.account",
        "description": "Canonical account record for tenant and workspace governance across the platform.",
        "tags": [
          "universal",
          "organization",
          "tenant"
        ],
        "traits": [
          {
            "reference": "content/Labelled",
            "alias": "OrganizationLabel",
            "parameters": {}
          },
          {
            "reference": "lifecycle/Stateful",
            "alias": null,
            "parameters": {
              "states": [
                "prospect",
                "onboarding",
                "active",
                "churned"
              ],
              "initialState": "prospect"
            }
          },
          {
            "reference": "structural/Ownerable",
            "alias": null,
            "parameters": {
              "ownerTypes": [
                "parent_organization",
                "reseller",
                "platform"
              ],
              "primaryOwnerType": "parent_organization",
              "allowTransfer": true
            }
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": null,
            "parameters": {
              "recordedEvents": [
                "created",
                "plan_upgraded",
                "plan_downgraded",
                "ownership_transferred"
              ],
              "timezone": "UTC"
            }
          },
          {
            "reference": "behavioral/Taggable",
            "alias": null,
            "parameters": {
              "maxTags": 16,
              "allowCustomTags": false,
              "allowedTags": [
                "enterprise",
                "smb",
                "nonprofit",
                "startup",
                "strategic"
              ],
              "caseSensitive": false
            }
          },
          {
            "reference": "core/Addressable",
            "alias": "OrganizationLocations",
            "parameters": {
              "roles": [
                "headquarters",
                "office",
                "warehouse",
                "branch"
              ],
              "defaultRole": "headquarters"
            }
          },
          {
            "reference": "core/Preferenceable",
            "alias": "OrganizationPreferences",
            "parameters": {
              "namespaces": [
                "notifications",
                "display",
                "privacy"
              ],
              "schemaVersion": "2.0.0",
              "registryNamespace": "org-preferences"
            }
          },
          {
            "reference": "core/Authable",
            "alias": "OrganizationAuthz",
            "parameters": {
              "hierarchyDepthLimit": 5
            }
          },
          {
            "reference": "core/Communicable",
            "alias": "OrganizationCommunications",
            "parameters": {}
          }
        ],
        "fields": [
          "organization_id",
          "domain",
          "plan_tier",
          "billing_status",
          "industry",
          "employee_count",
          "billing_contact_email",
          "data_residency",
          "owner_name"
        ],
        "semantics": {
          "description": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "TextBody",
              "maxLengthParameter": "maxDescriptionLength"
            }
          },
          "owner_id": {
            "semantic_type": "ownership.owner.id",
            "token_mapping": "tokenMap(ownership.owner.id)",
            "ui_hints": {
              "component": "OwnerReference",
              "ownerTypeField": "owner_type",
              "displayLabelField": "owner_name"
            }
          },
          "organization_id": {
            "semantic_type": "organization.id",
            "token_mapping": "tokenMap(organization.id.primary)"
          },
          "domain": {
            "semantic_type": "organization.domain",
            "token_mapping": "tokenMap(organization.domain.primary)"
          },
          "plan_tier": {
            "semantic_type": "organization.plan.tier",
            "token_mapping": "tokenMap(organization.plan.tier)"
          },
          "billing_status": {
            "semantic_type": "billing.account.status",
            "token_mapping": "tokenMap(billing.account.status)"
          },
          "employee_count": {
            "semantic_type": "organization.metrics.employee_count",
            "token_mapping": "tokenMap(metric.count.primary)"
          }
        },
        "tokens": {
          "organization.id.primary": "var(--text-strong)",
          "organization.domain.primary": "var(--text-strong)",
          "billing.account.status.good": "var(--status-success)",
          "billing.account.status.risk": "var(--status-warning)"
        },
        "metadata": {
          "owners": [
            "customer-success@oods.systems",
            "billing@oods.systems"
          ],
          "steward": "platform@oods.systems",
          "changelog": [
            {
              "version": "1.2.0",
              "date": "2025-11-20",
              "description": "Added Authable trait to expose membership and entitlement exports for tenant governance."
            },
            {
              "version": "1.1.0",
              "date": "2025-11-18",
              "description": "Added Addressable trait for headquarters, branch, office, and warehouse roles."
            },
            {
              "version": "1.0.0",
              "date": "2025-10-16",
              "description": "Initial Universal Quintet baseline."
            }
          ]
        },
        "visibility": "public",
        "source": "objects/core/Organization.object.yaml"
      },
      "Plan": {
        "name": "Plan",
        "version": "1.0.0",
        "domain": "saas.billing",
        "description": "Normalized plan definition capturing pricing, packaging, and entitlement metadata.",
        "tags": [
          "billing",
          "plan",
          "packaging"
        ],
        "traits": [
          {
            "reference": "SaaSBillingBillable",
            "alias": "Pricing",
            "parameters": {}
          },
          {
            "reference": "SaaSBillingMetered",
            "alias": "IncludedUsage",
            "parameters": {
              "unit": "seats",
              "rolloverStrategy": "none",
              "sampleWindowDays": 30
            }
          },
          {
            "reference": "structural/Ownerable",
            "alias": "PlanOwnership",
            "parameters": {}
          }
        ],
        "fields": [
          "plan_id",
          "product_family",
          "status",
          "feature_matrix",
          "add_on_ids",
          "upgrade_targets",
          "downgrade_targets",
          "notes",
          "owner_name"
        ],
        "semantics": {
          "plan_id": {
            "semantic_type": "billing.plan.id",
            "token_mapping": "tokenMap(billing.plan.id)"
          },
          "product_family": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(billing.plan.product_family)"
          },
          "owner_id": {
            "semantic_type": "ownership.owner.id",
            "token_mapping": "tokenMap(ownership.owner.id)",
            "ui_hints": {
              "component": "OwnerReference",
              "ownerTypeField": "owner_type",
              "displayLabelField": "owner_name"
            }
          },
          "status": {
            "semantic_type": "billing.plan.status",
            "token_mapping": "tokenMap(billing.plan.status)"
          },
          "feature_matrix": {
            "semantic_type": "billing.plan.feature_matrix",
            "token_mapping": "tokenMap(billing.plan.feature_matrix)"
          },
          "add_on_ids": {
            "semantic_type": "billing.plan.add_on_ids",
            "token_mapping": "tokenMap(billing.plan.add_on_ids)"
          },
          "upgrade_targets": {
            "semantic_type": "billing.plan.upgrade_targets",
            "token_mapping": "tokenMap(billing.plan.upgrade_targets)"
          },
          "downgrade_targets": {
            "semantic_type": "billing.plan.downgrade_targets",
            "token_mapping": "tokenMap(billing.plan.downgrade_targets)"
          },
          "notes": {
            "semantic_type": "billing.plan.notes",
            "token_mapping": "tokenMap(billing.plan.notes)"
          }
        },
        "tokens": {
          "billing.plan.id": "var(--cmp-text-strong)",
          "billing.plan.status": "var(--cmp-badge-text-info)",
          "billing.plan.product_family": "var(--cmp-text-subtle)"
        },
        "metadata": {
          "owners": [
            "product@oods.systems",
            "pricing@oods.systems"
          ],
          "maturity": "beta",
          "references": [
            {
              "R13.5 Canonical Model": "Subscription and Invoice"
            }
          ]
        },
        "visibility": "public",
        "source": "domains/saas-billing/objects/Plan.object.yaml"
      },
      "Product": {
        "name": "Product",
        "version": "1.1.0",
        "domain": "core.catalog",
        "description": "Canonical catalog entry combining pricing, lifecycle, and merchandising metadata.",
        "tags": [
          "universal",
          "product",
          "commerce",
          "taxonomy"
        ],
        "traits": [
          {
            "reference": "content/Labelled",
            "alias": "ProductLabel",
            "parameters": {}
          },
          {
            "reference": "lifecycle/Stateful",
            "alias": null,
            "parameters": {
              "states": [
                "draft",
                "in_review",
                "active",
                "retired"
              ],
              "initialState": "draft"
            }
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": null,
            "parameters": {
              "recordedEvents": [
                "created",
                "spec_updated",
                "price_changed",
                "retired"
              ],
              "timezone": "UTC"
            }
          },
          {
            "reference": "financial/Priceable",
            "alias": null,
            "parameters": {
              "supportedCurrencies": [
                "USD",
                "EUR",
                "GBP",
                "AUD"
              ],
              "defaultCurrency": "USD",
              "pricingModels": [
                "one_time",
                "subscription",
                "usage_based"
              ],
              "billingIntervals": [
                "one_time",
                "month",
                "year"
              ],
              "taxBehavior": "exclusive"
            }
          },
          {
            "reference": "core/Classifiable",
            "alias": "ProductClassification",
            "parameters": {
              "classification_mode": "taxonomy",
              "hierarchy_storage_model": "materialized_path",
              "tag_policy": "locked",
              "max_tags": 8,
              "require_primary_category": true
            }
          },
          {
            "reference": "behavioral/Searchable",
            "alias": null,
            "parameters": {
              "placeholder": "Search products...",
              "debounceMs": 300
            }
          },
          {
            "reference": "behavioral/Filterable",
            "alias": null,
            "parameters": {
              "filterMode": "immediate",
              "showFilterCount": true
            }
          },
          {
            "reference": "behavioral/Pageable",
            "alias": null,
            "parameters": {
              "defaultPageSize": 25,
              "pageSizeOptions": [
                10,
                25,
                50,
                100
              ]
            }
          }
        ],
        "fields": [
          "product_id",
          "sku",
          "inventory_status",
          "release_channel",
          "requires_subscription",
          "support_level",
          "summary_blurb"
        ],
        "semantics": {
          "description": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "TextBody",
              "maxLengthParameter": "maxDescriptionLength"
            }
          },
          "product_id": {
            "semantic_type": "product.id",
            "token_mapping": "tokenMap(product.id.primary)"
          },
          "sku": {
            "semantic_type": "product.sku",
            "token_mapping": "tokenMap(product.sku.primary)"
          },
          "inventory_status": {
            "semantic_type": "product.inventory.status",
            "token_mapping": "tokenMap(inventory.status.*)"
          },
          "release_channel": {
            "semantic_type": "product.release.channel",
            "token_mapping": "tokenMap(product.release.channel)"
          },
          "requires_subscription": {
            "semantic_type": "product.access.requires_subscription",
            "token_mapping": "tokenMap(product.access.subscription)"
          }
        },
        "tokens": {
          "product.sku.primary": "var(--text-strong)",
          "inventory.status.low_stock": "var(--status-warning)",
          "inventory.status.discontinued": "var(--status-danger)"
        },
        "metadata": {
          "owners": [
            "product@oods.systems",
            "commerce@oods.systems"
          ],
          "steward": "merchandising@oods.systems",
          "changelog": [
            {
              "version": "1.1.0",
              "date": "2025-11-18",
              "description": "Added Classifiable trait (taxonomy mode) for hierarchical categories + breadcrumbs."
            },
            {
              "version": "1.0.0",
              "date": "2025-10-16",
              "description": "Initial Universal Quintet baseline."
            }
          ]
        },
        "visibility": "public",
        "source": "objects/core/Product.object.yaml"
      },
      "Relationship": {
        "name": "Relationship",
        "version": "1.1.0",
        "domain": "core.graph",
        "description": "Canonical graph edge linking two entities with lifecycle, ownership, and tagging semantics.",
        "tags": [
          "universal",
          "relationship",
          "graph"
        ],
        "traits": [
          {
            "reference": "content/Labelled",
            "alias": "RelationshipLabel",
            "parameters": {}
          },
          {
            "reference": "lifecycle/Stateful",
            "alias": null,
            "parameters": {
              "states": [
                "proposed",
                "active",
                "paused",
                "completed",
                "terminated"
              ],
              "initialState": "proposed"
            }
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": null,
            "parameters": {
              "recordedEvents": [
                "created",
                "activated",
                "paused",
                "terminated",
                "reactivated"
              ],
              "timezone": "UTC"
            }
          },
          {
            "reference": "structural/Ownerable",
            "alias": null,
            "parameters": {
              "ownerTypes": [
                "organization",
                "team",
                "platform"
              ],
              "primaryOwnerType": "organization",
              "allowTransfer": true
            }
          },
          {
            "reference": "behavioral/Taggable",
            "alias": null,
            "parameters": {
              "maxTags": 10,
              "allowCustomTags": true,
              "allowedTags": [
                "primary",
                "secondary",
                "inferred",
                "manual",
                "pending_review"
              ],
              "caseSensitive": false
            }
          },
          {
            "reference": "viz/MarkGraph",
            "alias": null,
            "parameters": {
              "title": "Connected relationships",
              "description": "This relationship and the others that share one of its endpoints.",
              "chart": {
                "chartType": "force_graph",
                "source": "edge-array",
                "dataField": "neighborhood",
                "edges": {
                  "source": "source_id",
                  "target": "target_id",
                  "bidirectionalField": "is_bidirectional"
                },
                "sampleRows": [
                  {
                    "source_id": "example-team",
                    "target_id": "example-project",
                    "is_bidirectional": false
                  },
                  {
                    "source_id": "example-project",
                    "target_id": "example-document",
                    "is_bidirectional": true
                  }
                ]
              }
            }
          }
        ],
        "fields": [
          "neighborhood",
          "relationship_id",
          "source_id",
          "source_name",
          "target_id",
          "target_name",
          "relationship_type",
          "direction",
          "strength",
          "origin_source",
          "is_bidirectional",
          "owner_name"
        ],
        "semantics": {
          "description": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(text.body.*)",
            "ui_hints": {
              "component": "TextBody",
              "maxLengthParameter": "maxDescriptionLength"
            }
          },
          "relationship_id": {
            "semantic_type": "graph.relationship.id",
            "token_mapping": "tokenMap(graph.relationship.id)"
          },
          "source_id": {
            "semantic_type": "graph.relationship.source_id",
            "token_mapping": "tokenMap(graph.relationship.id)",
            "ui_hints": {
              "displayLabelField": "source_name"
            }
          },
          "target_id": {
            "semantic_type": "graph.relationship.target_id",
            "token_mapping": "tokenMap(graph.relationship.id)",
            "ui_hints": {
              "displayLabelField": "target_name"
            }
          },
          "owner_id": {
            "semantic_type": "ownership.owner.id",
            "token_mapping": "tokenMap(ownership.owner.id)",
            "ui_hints": {
              "component": "OwnerReference",
              "ownerTypeField": "owner_type",
              "displayLabelField": "owner_name"
            }
          },
          "relationship_type": {
            "semantic_type": "graph.relationship.type",
            "token_mapping": "tokenMap(graph.relationship.type)"
          },
          "direction": {
            "semantic_type": "graph.relationship.direction",
            "token_mapping": "tokenMap(graph.relationship.direction)"
          },
          "strength": {
            "semantic_type": "graph.relationship.strength",
            "token_mapping": "tokenMap(graph.relationship.strength)"
          },
          "origin_source": {
            "semantic_type": "graph.relationship.origin",
            "token_mapping": "tokenMap(graph.relationship.origin)"
          }
        },
        "tokens": {
          "graph.relationship.type": "var(--graph-relationship-type)",
          "graph.relationship.direction": "var(--text-default)",
          "graph.relationship.strength.high": "var(--status-success)"
        },
        "metadata": {
          "owners": [
            "data@oods.systems",
            "platform@oods.systems"
          ],
          "steward": "graph@oods.systems",
          "changelog": [
            {
              "version": "1.1.0",
              "date": "2026-09-14",
              "description": "Declared neighborhood edge array and a read-only graph of explicitly synthetic connected relationship examples."
            },
            {
              "version": "1.0.0",
              "date": "2025-10-16",
              "description": "Initial Universal Quintet baseline."
            }
          ]
        },
        "visibility": "public",
        "source": "objects/core/Relationship.object.yaml"
      },
      "Subscription": {
        "name": "Subscription",
        "version": "2.0.0",
        "domain": "core.billing",
        "description": "Canonical subscription record composing lifecycle, billing, and cancellation semantics.",
        "tags": [
          "billing",
          "lifecycle",
          "monetization"
        ],
        "traits": [
          {
            "reference": "lifecycle/Stateful",
            "alias": "SubscriptionLifecycle",
            "parameters": {
              "states": [
                "future",
                "trialing",
                "active",
                "paused",
                "pending_cancellation",
                "past_due",
                "unpaid",
                "terminated"
              ],
              "initialState": "future"
            }
          },
          {
            "reference": "lifecycle/Cancellable",
            "alias": "SubscriptionCancellation",
            "parameters": {
              "allowCancellationAfterStart": true,
              "requireReason": false
            }
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": "BillingCycleTimeline",
            "parameters": {
              "recordedEvents": [
                "billing_cycle_started",
                "billing_cycle_completed",
                "payment_received",
                "cancellation_requested"
              ],
              "timezone": "UTC"
            }
          },
          {
            "reference": "financial/Billable",
            "alias": "SubscriptionBilling",
            "parameters": {
              "defaultCurrency": "usd",
              "billingIntervals": [
                "monthly",
                "yearly"
              ],
              "minorUnits": 100,
              "supportProration": true,
              "prorationBehavior": "always_invoice"
            }
          },
          {
            "reference": "lifecycle/Archivable",
            "alias": "SubscriptionArchive",
            "parameters": {
              "gracePeriodDays": 30,
              "retainHistory": true,
              "restoreWindowDays": 30
            }
          },
          {
            "reference": "viz/MarkBar",
            "alias": null,
            "parameters": {
              "title": "Payment amounts",
              "description": "Payments recorded for this subscription, in its currency.",
              "chart": {
                "chartType": "bar",
                "source": "payment-events",
                "dateFields": [
                  "last_payment_at",
                  "next_payment_due_at"
                ],
                "amountField": "amount",
                "minorUnits": 100,
                "currencyField": "currency"
              }
            }
          }
        ],
        "fields": [
          "subscription_id",
          "plan_name",
          "plan_code",
          "plan_interval",
          "customer_name",
          "customer_email",
          "status",
          "cancel_at_period_end",
          "cancellation_reason",
          "cancellation_requested_at",
          "amount",
          "currency",
          "billing_interval",
          "current_period_start",
          "current_period_end",
          "current_period_progress",
          "next_payment_due_at",
          "payment_history"
        ],
        "semantics": {
          "subscription_id": {
            "semantic_type": "billing.subscription.id",
            "token_mapping": "tokenMap(billing.subscription.id)"
          },
          "plan_name": {
            "semantic_type": "billing.plan.name",
            "token_mapping": "tokenMap(billing.plan.name)"
          },
          "plan_code": {
            "semantic_type": "billing.plan.code",
            "token_mapping": "tokenMap(billing.plan.code)"
          },
          "plan_interval": {
            "semantic_type": "billing.plan.interval",
            "token_mapping": "tokenMap(billing.plan.interval)"
          },
          "customer_name": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(customer.account.name)"
          },
          "customer_email": {
            "semantic_type": "customer.account.email",
            "token_mapping": "tokenMap(customer.account.email)"
          },
          "status": {
            "semantic_type": "billing.subscription.status",
            "token_mapping": "tokenMap(billing.subscription.status.*)"
          },
          "cancel_at_period_end": {
            "semantic_type": "billing.subscription.cancel_at_period_end",
            "token_mapping": "tokenMap(billing.subscription.cancel_at_period_end)"
          },
          "cancellation_reason": {
            "semantic_type": "billing.subscription.cancellation_reason",
            "token_mapping": "tokenMap(billing.subscription.cancellation_reason)"
          },
          "cancellation_requested_at": {
            "semantic_type": "billing.subscription.cancellation_requested_at",
            "token_mapping": "tokenMap(billing.subscription.cancellation_requested_at)"
          },
          "amount": {
            "semantic_type": "billing.plan.amount",
            "token_mapping": "tokenMap(billing.plan.amount)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnitsParameter": "minorUnits"
            }
          },
          "currency": {
            "semantic_type": "billing.plan.currency",
            "token_mapping": "tokenMap(billing.plan.currency)"
          },
          "billing_interval": {
            "semantic_type": "billing.subscription.interval",
            "token_mapping": "tokenMap(billing.subscription.interval)"
          },
          "current_period_start": {
            "semantic_type": "billing.subscription.current_period_start",
            "token_mapping": "tokenMap(billing.subscription.current_period_start)"
          },
          "current_period_end": {
            "semantic_type": "billing.subscription.current_period_end",
            "token_mapping": "tokenMap(billing.subscription.current_period_end)"
          },
          "current_period_progress": {
            "semantic_type": "billing.subscription.current_period_progress",
            "token_mapping": "tokenMap(billing.subscription.current_period_progress)"
          },
          "last_payment_at": {
            "semantic_type": "billing.subscription.last_payment_at",
            "token_mapping": "tokenMap(billing.subscription.last_payment_at)"
          },
          "next_payment_due_at": {
            "semantic_type": "billing.subscription.next_payment_due_at",
            "token_mapping": "tokenMap(billing.subscription.next_payment_due_at)"
          }
        },
        "tokens": {
          "billing.subscription.status.future": "var(--semantic-info)",
          "billing.subscription.status.trialing": "var(--semantic-info)",
          "billing.subscription.status.active": "var(--semantic-success)",
          "billing.subscription.status.paused": "var(--semantic-warning)",
          "billing.subscription.status.pending_cancellation": "var(--semantic-info)",
          "billing.subscription.status.past_due": "var(--semantic-danger)",
          "billing.subscription.status.unpaid": "var(--semantic-danger)",
          "billing.subscription.status.terminated": "var(--semantic-neutral)",
          "billing.subscription.interval.monthly": "var(--text-subtle)",
          "billing.plan.amount": "var(--text-strong)"
        },
        "metadata": {
          "owners": [
            "billing@oods.systems",
            "lifecycle@oods.systems"
          ],
          "steward": "design@oods.systems",
          "maturity": "beta",
          "changelog": [
            {
              "version": "2.0.0",
              "date": "2026-06-24",
              "description": "Converge status onto the canonical Stripe-literal extend-8 state set. Replace the consolidated `delinquent` with `past_due` (retries ongoing → grace access) + `unpaid` (retries exhausted → access revoked). BREAKING: `delinquent` is removed from the status enum. Source: docs.stripe.com/api/subscriptions/object."
            },
            {
              "version": "1.0.0",
              "date": "2025-10-21",
              "description": "Initial subscription composition integrating State, Cancellation, Billing, and Timeline traits."
            }
          ]
        },
        "visibility": "public",
        "source": "objects/core/Subscription.object.yaml"
      },
      "Transaction": {
        "name": "Transaction",
        "version": "1.1.0",
        "domain": "core.commerce",
        "description": "Canonical transaction record tracking monetary movement, lifecycle, and audit metadata.",
        "tags": [
          "universal",
          "transaction",
          "commerce"
        ],
        "traits": [
          {
            "reference": "lifecycle/Stateful",
            "alias": null,
            "parameters": {
              "states": [
                "pending",
                "authorized",
                "settled",
                "failed",
                "refunded",
                "cancelled"
              ],
              "initialState": "pending"
            }
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": null,
            "parameters": {
              "recordedEvents": [
                "initiated",
                "authorized",
                "settled",
                "refunded",
                "failed"
              ],
              "timezone": "UTC"
            }
          },
          {
            "reference": "financial/Priceable",
            "alias": null,
            "parameters": {
              "supportedCurrencies": [
                "USD",
                "EUR",
                "GBP",
                "JPY",
                "AUD"
              ],
              "defaultCurrency": "USD",
              "pricingModels": [
                "one_time",
                "usage_based"
              ],
              "billingIntervals": [
                "one_time"
              ],
              "taxBehavior": "exclusive"
            }
          },
          {
            "reference": "lifecycle/Cancellable",
            "alias": null,
            "parameters": {
              "allowCancellationAfterStart": false,
              "cancellationWindowHours": 24,
              "requireReason": true,
              "allowedReasons": [
                "customer_request",
                "suspected_fraud",
                "duplicate_charge",
                "payment_method_error"
              ]
            }
          },
          {
            "reference": "lifecycle/Archivable",
            "alias": null,
            "parameters": {
              "gracePeriodDays": 365,
              "retainHistory": true,
              "restoreWindowDays": 30
            }
          }
        ],
        "fields": [
          "transaction_id",
          "user_id",
          "user_name",
          "organization_id",
          "organization_name",
          "occurred_at",
          "payment_method",
          "channel",
          "payment_reference",
          "description",
          "risk_score"
        ],
        "semantics": {
          "transaction_id": {
            "semantic_type": "commerce.transaction.id",
            "token_mapping": "tokenMap(commerce.transaction.id)"
          },
          "user_id": {
            "semantic_type": "identity.user.id",
            "token_mapping": "tokenMap(identity.id.primary)",
            "ui_hints": {
              "displayLabelField": "user_name"
            }
          },
          "user_name": {
            "semantic_type": "identity.user.name",
            "token_mapping": "tokenMap(identity.name.primary)"
          },
          "organization_id": {
            "semantic_type": "organization.id",
            "token_mapping": "tokenMap(organization.id.primary)",
            "ui_hints": {
              "displayLabelField": "organization_name"
            }
          },
          "organization_name": {
            "semantic_type": "organization.name",
            "token_mapping": "tokenMap(organization.name.primary)"
          },
          "description": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(commerce.transaction.description)"
          },
          "occurred_at": {
            "semantic_type": "commerce.transaction.timestamp",
            "token_mapping": "tokenMap(commerce.transaction.timestamp)"
          },
          "payment_method": {
            "semantic_type": "commerce.payment.method",
            "token_mapping": "tokenMap(commerce.payment.method)"
          },
          "channel": {
            "semantic_type": "commerce.transaction.channel",
            "token_mapping": "tokenMap(commerce.transaction.channel)"
          },
          "payment_reference": {
            "semantic_type": "text.label",
            "token_mapping": "tokenMap(commerce.transaction.id)",
            "ui_hints": {
              "displayFallbackField": "transaction_id"
            }
          },
          "risk_score": {
            "semantic_type": "risk.transaction.score",
            "token_mapping": "tokenMap(risk.score.primary)"
          }
        },
        "tokens": {
          "commerce.transaction.id": "var(--text-strong)",
          "commerce.transaction.channel.partner": "var(--status-info)",
          "risk.score.primary": "var(--status-warning)"
        },
        "metadata": {
          "owners": [
            "finance@oods.systems",
            "risk@oods.systems"
          ],
          "steward": "platform@oods.systems",
          "changelog": [
            {
              "version": "1.1.0",
              "date": "2026-09-20",
              "description": "Name transactions by the optional payment reference, falling back to transaction_id for display only."
            },
            {
              "version": "1.0.0",
              "date": "2025-10-16",
              "description": "Initial Universal Quintet baseline."
            }
          ]
        },
        "visibility": "public",
        "source": "objects/core/Transaction.object.yaml"
      },
      "Usage": {
        "name": "Usage",
        "version": "1.0.0",
        "domain": "saas.billing",
        "description": "Metered usage snapshot for consumption based billing supporting trend analysis and overage forecasting.",
        "tags": [
          "billing",
          "usage",
          "analytics"
        ],
        "traits": [
          {
            "reference": "SaaSBillingMetered",
            "alias": "MeterReading",
            "parameters": {
              "unit": "api_calls",
              "rolloverStrategy": "expire",
              "sampleWindowDays": 7
            }
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": "UsageAudit",
            "parameters": {
              "recordedEvents": [
                "reading_captured",
                "anomaly_detected",
                "reset"
              ],
              "timezone": "UTC",
              "allowNullUpdatedAt": true
            }
          },
          {
            "reference": "viz/MarkLine",
            "alias": null,
            "parameters": {
              "title": "Usage readings",
              "description": "Readings recorded for this meter, by the time each was taken.",
              "chart": {
                "chartType": "line",
                "source": "record-array",
                "dataField": "samples",
                "encodings": {
                  "x": {
                    "field": "timestamp",
                    "scale": "temporal",
                    "title": "Recorded at"
                  },
                  "y": {
                    "field": "value",
                    "titleField": "unit_label"
                  }
                },
                "sampleRows": [
                  {
                    "timestamp": "2025-06-15T00:00:00Z",
                    "value": 1200
                  },
                  {
                    "timestamp": "2025-06-20T00:00:00Z",
                    "value": 1800
                  },
                  {
                    "timestamp": "2025-06-25T00:00:00Z",
                    "value": 1500
                  }
                ]
              }
            }
          }
        ],
        "fields": [
          "usage_id",
          "subscription_id",
          "customer_name",
          "meter_id",
          "provider",
          "status",
          "trend_percent",
          "currency",
          "variance_minor",
          "last_reported_at",
          "anomalies"
        ],
        "semantics": {
          "meter_name": {
            "semantic_type": "text.label",
            "token_mapping": "tokenMap(billing.usage.meter_name)"
          },
          "usage_id": {
            "semantic_type": "billing.usage.id",
            "token_mapping": "tokenMap(billing.usage.id)"
          },
          "subscription_id": {
            "semantic_type": "billing.usage.subscription_id",
            "token_mapping": "tokenMap(billing.usage.subscription_id)"
          },
          "customer_name": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(billing.usage.customer_name)"
          },
          "meter_id": {
            "semantic_type": "billing.usage.meter_id",
            "token_mapping": "tokenMap(billing.usage.meter_id)"
          },
          "provider": {
            "semantic_type": "billing.usage.provider",
            "token_mapping": "tokenMap(billing.usage.provider)"
          },
          "status": {
            "semantic_type": "billing.usage.status",
            "token_mapping": "tokenMap(billing.usage.status)"
          },
          "trend_percent": {
            "semantic_type": "billing.usage.trend_percent",
            "token_mapping": "tokenMap(billing.usage.trend_percent)",
            "ui_hints": {
              "format": "percent"
            }
          },
          "currency": {
            "semantic_type": "billing.usage.currency",
            "token_mapping": "tokenMap(billing.usage.currency)"
          },
          "variance_minor": {
            "semantic_type": "billing.usage.variance_minor",
            "token_mapping": "tokenMap(billing.usage.variance_minor)",
            "ui_hints": {
              "component": "CurrencyAmount",
              "currencyField": "currency",
              "minorUnits": 100
            }
          },
          "last_reported_at": {
            "semantic_type": "billing.usage.last_reported_at",
            "token_mapping": "tokenMap(billing.usage.last_reported_at)"
          },
          "anomalies": {
            "semantic_type": "billing.usage.anomalies",
            "token_mapping": "tokenMap(billing.usage.anomalies)"
          }
        },
        "tokens": {
          "billing.usage.status.ok": "var(--cmp-badge-text-success)",
          "billing.usage.status.delayed": "var(--cmp-badge-text-warning)",
          "billing.usage.status.investigating": "var(--cmp-badge-text-critical)",
          "billing.usage.trend_percent": "var(--cmp-text-accent)"
        },
        "metadata": {
          "owners": [
            "analytics@oods.systems",
            "product-ops@oods.systems"
          ],
          "maturity": "beta",
          "references": [
            {
              "R13.5 Canonical Model": "Subscription and Invoice"
            }
          ]
        },
        "visibility": "public",
        "source": "domains/saas-billing/objects/Usage.object.yaml"
      },
      "User": {
        "name": "User",
        "version": "1.4.0",
        "domain": "core.identity",
        "description": "Canonical identity record representing a platform user across lifecycle contexts.",
        "tags": [
          "universal",
          "identity",
          "core"
        ],
        "traits": [
          {
            "reference": "lifecycle/Stateful",
            "alias": "UserLifecycle",
            "parameters": {
              "states": [
                "invited",
                "active",
                "suspended",
                "deactivated"
              ],
              "initialState": "active"
            }
          },
          {
            "reference": "lifecycle/Timestampable",
            "alias": "AuditTrail",
            "parameters": {
              "recordedEvents": [
                "created",
                "profile_updated",
                "status_changed",
                "role_updated"
              ],
              "timezone": "UTC",
              "allowNullUpdatedAt": false
            }
          },
          {
            "reference": "behavioral/Taggable",
            "alias": "AffinityTags",
            "parameters": {
              "maxTags": 12,
              "allowCustomTags": false,
              "allowedTags": [
                "admin",
                "beta_tester",
                "vip",
                "suspended"
              ],
              "caseSensitive": false
            }
          },
          {
            "reference": "core/Addressable",
            "alias": "UserAddresses",
            "parameters": {
              "roles": [
                "home",
                "billing",
                "shipping"
              ],
              "defaultRole": "home"
            }
          },
          {
            "reference": "core/Preferenceable",
            "alias": "UserPreferences",
            "parameters": {
              "namespaces": [
                "theme",
                "notifications",
                "display",
                "privacy"
              ],
              "schemaVersion": "2.0.0",
              "registryNamespace": "user-preferences"
            }
          },
          {
            "reference": "core/Authable",
            "alias": "UserAuthz",
            "parameters": {
              "hierarchyDepthLimit": 5
            }
          },
          {
            "reference": "core/Communicable",
            "alias": "UserCommunications",
            "parameters": {}
          }
        ],
        "fields": [
          "user_id",
          "name",
          "preferred_name",
          "description",
          "primary_email",
          "role",
          "timezone"
        ],
        "semantics": {
          "user_id": {
            "semantic_type": "identity.user.id",
            "token_mapping": "tokenMap(identity.id.primary)"
          },
          "name": {
            "semantic_type": "identity.user.name",
            "token_mapping": "tokenMap(identity.name.primary)"
          },
          "preferred_name": {
            "semantic_type": "identity.user.name_preferred",
            "token_mapping": "tokenMap(identity.name.preferred)"
          },
          "description": {
            "semantic_type": "text.summary",
            "token_mapping": "tokenMap(identity.description.summary)"
          },
          "primary_email": {
            "semantic_type": "identity.user.email",
            "token_mapping": "tokenMap(identity.email.primary)"
          },
          "role": {
            "semantic_type": "identity.user.role",
            "token_mapping": "tokenMap(identity.role.*)"
          },
          "timezone": {
            "semantic_type": "identity.user.timezone",
            "token_mapping": "tokenMap(identity.timezone.primary)"
          }
        },
        "tokens": {
          "identity.id.primary": "var(--text-strong)",
          "identity.name.primary": "var(--text-strong)",
          "identity.email.primary": "var(--text-subtle)",
          "identity.role.admin": "var(--status-info)",
          "identity.timezone.primary": "var(--text-muted)",
          "identity.description.summary": "var(--text-subtle)"
        },
        "metadata": {
          "owners": [
            "identity@oods.systems",
            "platform@oods.systems"
          ],
          "steward": "design@oods.systems",
          "maturity": "stable",
          "changelog": [
            {
              "version": "1.4.0",
              "date": "2025-11-20",
              "description": "Composed Authable trait to attach RBAC memberships and entitlement exports."
            },
            {
              "version": "1.3.0",
              "date": "2025-11-19",
              "description": "Added Preferenceable trait for schema-governed user preferences (theme, notifications, display, privacy)."
            },
            {
              "version": "1.2.0",
              "date": "2025-11-18",
              "description": "Added Addressable trait for multi-role user addresses (home, billing, shipping)."
            },
            {
              "version": "1.1.0",
              "date": "2025-10-18",
              "description": "Simplified composition for view engine integration (Stateful, Timestampable, Taggable)."
            },
            {
              "version": "1.0.0",
              "date": "2025-10-16",
              "description": "Initial Universal Quintet baseline."
            }
          ]
        },
        "visibility": "public",
        "source": "objects/core/User.object.yaml"
      }
    },
    "generatedAt": "2026-10-08T15:15:29.847Z",
    "detail": "full",
    "registry": {
      "source": "live-registry",
      "objects": [
        "Article",
        "Invoice",
        "Media",
        "Organization",
        "Plan",
        "Product",
        "Relationship",
        "Subscription",
        "Transaction",
        "Usage",
        "User"
      ],
      "hiddenInternal": 5,
      "traits": [
        "Addressable",
        "Archivable",
        "Assessable",
        "Auditable",
        "Authable",
        "Billable",
        "Cancellable",
        "Classifiable",
        "Colorized",
        "Communicable",
        "EncodingColor",
        "EncodingOpacity",
        "EncodingPositionX",
        "EncodingPositionY",
        "EncodingShape",
        "EncodingSize",
        "Filterable",
        "Geocodable",
        "InteractionHighlight",
        "InteractionTooltip",
        "Labelled",
        "LayoutConcat",
        "LayoutFacet",
        "LayoutLayer",
        "MarkArea",
        "MarkBar",
        "MarkGraph",
        "MarkLine",
        "MarkPoint",
        "MarkRect",
        "Ownerable",
        "Pageable",
        "Preferenceable",
        "Priceable",
        "Provenanced",
        "SaaSBillingBillable",
        "SaaSBillingMetered",
        "SaaSBillingPayable",
        "SaaSBillingRefundable",
        "ScaleLinear",
        "ScaleTemporal",
        "ScatterPlot",
        "Searchable",
        "Sortable",
        "Stateful",
        "Statusable",
        "Supersedable",
        "Taggable",
        "Timestampable"
      ],
      "issues": []
    },
    "etag": "2a8386f5eb7f0d813b10d717453b222d2c25078d2195053c238973a5f452ab12"
  }
}
