@revturbine/cli 0.16.2 → 0.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +628 -375
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -18,8 +18,8 @@ import { z as z5 } from "zod";
18
18
  import { z as z4 } from "zod";
19
19
  import { z as z6 } from "zod";
20
20
  import { z as z7 } from "zod";
21
- import { z as z8 } from "zod";
22
21
  import { z as z9 } from "zod";
22
+ import { z as z8 } from "zod";
23
23
  import { z as z10 } from "zod";
24
24
  import { z as z11 } from "zod";
25
25
  import { z as z12 } from "zod";
@@ -51,7 +51,12 @@ var DataClassification = {
51
51
  Financial: { "x-revturbine-data-classification": "financial" },
52
52
  Unrestricted: { "x-revturbine-data-classification": "unrestricted" }
53
53
  };
54
+ var SCHEMA_EXPOSURE_META_KEY = "x-revturbine-schema-exposure";
54
55
  var READ_ONLY_META_KEY = "readOnly";
56
+ var DECISION_ONLY_META_KEY = "x-revturbine-decision-only";
57
+ var DecisionOnly = { [DECISION_ONLY_META_KEY]: true };
58
+ var ClientSafe = { [SCHEMA_EXPOSURE_META_KEY]: SchemaExposure.External };
59
+ var ServerOnly = { [SCHEMA_EXPOSURE_META_KEY]: SchemaExposure.Internal };
55
60
  function toWritableSchema(schema) {
56
61
  const writableShape = {};
57
62
  for (const [fieldName, fieldSchema] of Object.entries(schema.shape)) {
@@ -1334,6 +1339,9 @@ var PlacementPayloadSchema = IdField.merge(TimestampFields).merge(TenantIdField)
1334
1339
  max_per_period: z7.number().int().min(0).nullable().default(null).meta(Unrestricted4),
1335
1340
  max_period_unit: CapPeriodSchema.default("session").meta(Unrestricted4),
1336
1341
  cooldown_after_dismiss_days: z7.number().int().min(0).default(7).meta(Unrestricted4),
1342
+ // Per-payload remind-me-later (defer) window override, in minutes. Null =
1343
+ // inherit the tenant default (`remindLaterMinutes`, 60). Plan 167 REQ-6 / Q-3.
1344
+ remind_later_minutes: z7.number().int().min(0).nullable().default(null).meta(Unrestricted4),
1337
1345
  recommendation_strategy: z7.enum(["next_tier_up", "best_value", "custom"]).optional().default("next_tier_up").meta(Unrestricted4),
1338
1346
  recommendation_plan_override: z7.string().optional().meta(Unrestricted4)
1339
1347
  }).meta(
@@ -1532,256 +1540,72 @@ var placementPaths = {
1532
1540
  };
1533
1541
  var { Unrestricted: Unrestricted5, Pii } = DataClassification;
1534
1542
  var { Persisted: Persisted5, Transient: Transient5 } = SchemaPersistence;
1535
- var { External: External5 } = SchemaExposure;
1536
- var UserTrialStatusSchema = z8.object({
1537
- in_trial: z8.boolean().meta(Unrestricted5),
1538
- trial_type: z8.string().optional().meta(Unrestricted5),
1539
- plan_handle: z8.string().optional().meta(Unrestricted5),
1540
- // 'converted' reflects a server-side analytic-event transition
1541
- // (typically a Stripe webhook like `customer.subscription.created`
1542
- // or `invoice.payment_succeeded` against a trialing subscription)
1543
- // that the control plane processes to flip TrialInstance.status.
1544
- // The SDK reads this state from the decision-API response — it does
1545
- // NOT derive 'converted' client-side. trial_lifecycle.v1 rules
1546
- // matching on 'trial_converted' fire while the user's status carries
1547
- // this value, enabling conversion-celebration / receipt placements.
1548
- state: z8.enum(["active", "running_out", "expired", "converted", "none"]).optional().meta(Unrestricted5),
1549
- /**
1550
- * Trial limit model — mirrors the rule's `trial_limit_type`. The
1551
- * SDK uses this to decide which numeric fields below to surface;
1552
- * the placement-resolver gates `trial_ending(days_before_end)`
1553
- * only when `trial_limit_type === 'time'`.
1554
- */
1555
- trial_limit_type: z8.enum(["time", "usage"]).optional().meta(Unrestricted5),
1556
- /**
1557
- * Universal progress metric, 0..100. Computed by
1558
- * `deriveLocalTrialStatusFromInstance` from elapsed days
1559
- * (time-based) or consumed/limit (usage-based). Trial rule
1560
- * modules + placement-resolver supersession consume this field
1561
- * so they don't have to branch on the limit type.
1562
- */
1563
- progress_percent: z8.number().min(0).max(100).optional().meta(Unrestricted5),
1564
- // Time-based numeric fields. Populated when trial_limit_type='time'.
1565
- day_number: z8.number().int().min(0).optional().meta(Unrestricted5),
1566
- days_remaining: z8.number().int().min(0).optional().meta(Unrestricted5),
1567
- // Usage-based numeric fields. Populated when trial_limit_type='usage'.
1568
- usage_entitlement_handle: z8.string().optional().meta(Unrestricted5),
1569
- usage_consumed: z8.number().int().min(0).optional().meta(Unrestricted5),
1570
- usage_remaining: z8.number().int().min(0).optional().meta(Unrestricted5),
1571
- usage_limit: z8.number().int().min(0).optional().meta(Unrestricted5)
1572
- }).meta(
1573
- { id: "UserTrialStatus", "x-revturbine-schema-persistence": Transient5, "x-revturbine-schema-exposure": External5 }
1574
- );
1575
- var UserUsageEntrySchema = z8.object({
1576
- entitlement_handle: z8.string().min(1).meta(Unrestricted5),
1577
- unit: z8.string().min(1).meta(Unrestricted5),
1578
- amount: z8.number().min(0).meta(Unrestricted5),
1579
- limit: z8.number().min(0).optional().meta(Unrestricted5),
1580
- reset_date: z8.string().optional().meta(Unrestricted5)
1581
- }).meta(
1582
- { id: "UserUsageEntry", "x-revturbine-schema-persistence": Transient5, "x-revturbine-schema-exposure": External5 }
1583
- );
1584
- var UserPlanContextSchema = z8.object({
1585
- id: z8.string().min(1).meta(Unrestricted5),
1586
- name: z8.string().min(1).meta(Unrestricted5),
1587
- price: z8.string().optional().meta(Unrestricted5),
1588
- billing_period: z8.enum(["monthly", "annual", "none"]).optional().meta(Unrestricted5)
1589
- }).meta(
1590
- { id: "UserPlanContext", "x-revturbine-schema-persistence": Transient5, "x-revturbine-schema-exposure": External5 }
1591
- );
1592
- var UserInstanceContextSchema = z8.object({
1593
- product_instance_id: z8.string().min(1).meta(Unrestricted5),
1594
- user_id: z8.string().min(1).meta(Pii),
1595
- plan: UserPlanContextSchema.optional().meta(Unrestricted5),
1596
- /** Usage entries for this instance, keyed by entitlement handle. */
1597
- usage: z8.record(z8.string(), UserUsageEntrySchema).default({}).meta(Unrestricted5),
1598
- trial: UserTrialStatusSchema.optional().meta(Unrestricted5),
1599
- /** Entitlements resolved at this instance level, keyed by handle. */
1600
- entitlements: z8.record(z8.string(), z8.union([z8.boolean(), EntitlementGrantSchema])).default({}).meta(Unrestricted5)
1601
- }).meta(
1602
- {
1603
- id: "UserInstanceContext",
1604
- "x-revturbine-schema-persistence": Persisted5,
1605
- "x-revturbine-schema-exposure": External5
1606
- }
1607
- );
1608
- var UserContextSchema = IdField.merge(TenantIdField).merge(TimestampFields).extend({
1609
- user_id: z8.string().min(1).meta(Pii),
1610
- account_id: z8.string().min(1).nullable().optional().meta(Pii),
1611
- email: z8.string().email().nullable().optional().meta(Pii),
1612
- /** Optional email classification (e.g. `business`, `personal`). */
1613
- email_type: z8.string().optional().meta(Unrestricted5),
1614
- plan: UserPlanContextSchema.optional().meta(Unrestricted5),
1615
- /** Aggregate usage entries across all instances, keyed by handle. */
1616
- usage: z8.record(z8.string(), UserUsageEntrySchema).default({}).meta(Unrestricted5),
1617
- trial: UserTrialStatusSchema.optional().meta(Unrestricted5),
1618
- /**
1619
- * Billing-recovery signals (account-level). `payment_failed` reflects a
1620
- * hard payment failure (e.g. Stripe `invoice.payment_failed`);
1621
- * `payment_at_risk` an expiring / missing-backup payment method. They
1622
- * drive the Retention `qualifier` placement triggers
1623
- * (placement-studio-ui.md §3.7) — the SDK surfaces them onto the
1624
- * PlanProvider state the placement resolver reads. Omitted for users in
1625
- * good standing; a qualifier gate reads `=== true`, so an absent signal
1626
- * never fires the recovery placement.
1627
- */
1628
- payment_failed: z8.boolean().optional().meta(Unrestricted5),
1629
- payment_at_risk: z8.boolean().optional().meta(Unrestricted5),
1630
- /**
1631
- * The user's current tier per `capability_tier` entitlement, keyed by
1632
- * entitlement handle → tier handle (plan 138 TASK-4). Drives the
1633
- * `entitlement_gate.tier_threshold` placement trigger: the SDK surfaces
1634
- * this onto the EntitlementProvider state, and the resolver ranks the
1635
- * current tier against the entitlement's ordered ladder. Omitted for a
1636
- * user holding no tier (ranks below every threshold).
1637
- */
1638
- tiers: z8.record(z8.string(), z8.string()).optional().meta(Unrestricted5),
1639
- /** Account-level entitlements, keyed by handle. */
1640
- entitlements: z8.record(z8.string(), z8.union([z8.boolean(), EntitlementGrantSchema])).default({}).meta(Unrestricted5),
1641
- /** Per-instance breakdowns when the account has multiple product instances. */
1642
- instances: z8.array(UserInstanceContextSchema).optional().meta(Unrestricted5),
1643
- /** Customer-defined fields: role, app-level permissions, display prefs. */
1644
- custom: z8.record(z8.string(), z8.union([z8.string(), z8.number(), z8.boolean(), z8.null()])).default({}).meta(Pii),
1645
- /**
1646
- * Transient personalization token map.
1647
- *
1648
- * Holds SDK-derived tokens (plan_name, usage_current, etc.) merged with
1649
- * app-provided tokens. Not persisted to the backend — rebuilt on each
1650
- * SDK session from context + exported config.
1651
- */
1652
- personalization: z8.record(z8.string(), z8.union([z8.string(), z8.number()])).default({}).meta({ ...Unrestricted5, "x-revturbine-schema-persistence": Transient5 }),
1653
- // ── Derived-entitlement cache (plan 74 REQ-12/REQ-13) ──────────────
1654
- // `entitlements` above is the rule-evaluated projection — a CACHE, not
1655
- // source of truth. These stamps record what it was computed against so a
1656
- // read can detect staleness: recompute when the active config version
1657
- // moved on OR the context hash changed.
1658
- /** Active config version (activated change-set id / compiled-bundle stamp) the cache was computed against. */
1659
- derived_config_version: z8.string().nullable().optional().meta(Unrestricted5),
1660
- /** Deterministic `computeUserContextHash` of the inputs the cache was computed from (REQ-13 ETag value). */
1661
- context_hash: z8.string().nullable().optional().meta(Unrestricted5),
1662
- /** When the cached entitlements were last (re)computed. */
1663
- derived_computed_at: NullableDatetimeField.meta(Unrestricted5)
1664
- }).meta(
1665
- { id: "UserContext", "x-revturbine-schema-persistence": Persisted5, "x-revturbine-schema-exposure": External5 }
1666
- );
1667
- var userContextPaths = {
1668
- "/api/user-contexts": {
1669
- get: operation({
1670
- operationId: "listUserContexts",
1671
- requestParams: { query: ListQueryParamsSchema },
1672
- summary: "List user contexts",
1673
- tags: ["users"],
1674
- responses: { "200": { description: "User context list", content: { "application/json": { schema: ListEnvelope(UserContextSchema) } } } },
1675
- "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "list" } }
1676
- }),
1677
- // Upsert by (tenant_id, user_id): the SDK identify/setUserContext path
1678
- // writes the persisted context. The collection POST is the create-or-update
1679
- // entry point — the route resolves the existing row by (tenant_id, user_id)
1680
- // and applies an idempotent upsert (server-side, plan 74 TASK-4).
1681
- post: operation({
1682
- operationId: "createUserContext",
1683
- summary: "Create or upsert a user context",
1684
- tags: ["users"],
1685
- requestBody: { required: true, content: { "application/json": { schema: UserContextSchema } } },
1686
- responses: { "201": { description: "Created", content: { "application/json": { schema: UserContextSchema } } } },
1687
- "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "create" } }
1688
- })
1689
- },
1690
- "/api/user-contexts/{userContextId}": {
1691
- get: operation({
1692
- operationId: "getUserContext",
1693
- requestParams: { path: z8.object({ userContextId: z8.string() }) },
1694
- summary: "Get user context",
1695
- tags: ["users"],
1696
- responses: { "200": { description: "User context", content: { "application/json": { schema: UserContextSchema } } } },
1697
- "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "get" } }
1698
- }),
1699
- patch: operation({
1700
- operationId: "updateUserContext",
1701
- requestParams: { path: z8.object({ userContextId: z8.string() }) },
1702
- summary: "Update a user context",
1703
- tags: ["users"],
1704
- requestBody: { required: true, content: { "application/json": { schema: UserContextSchema.partial() } } },
1705
- responses: { "200": { description: "Updated", content: { "application/json": { schema: UserContextSchema } } } },
1706
- "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "update" } }
1707
- }),
1708
- // Delete path ships in v1 (plan 74 Q-1): a user context can be removed on
1709
- // request now; full by-email DSR tooling remains deferred (sdk.md §8).
1710
- delete: operation({
1711
- operationId: "deleteUserContext",
1712
- requestParams: { path: z8.object({ userContextId: z8.string() }) },
1713
- summary: "Delete a user context",
1714
- tags: ["users"],
1715
- responses: { "204": { description: "Deleted" } },
1716
- "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "delete" } }
1717
- })
1718
- }
1719
- };
1720
- var { Unrestricted: Unrestricted6, Pii: Pii2 } = DataClassification;
1721
- var { Persisted: Persisted6, Transient: Transient6 } = SchemaPersistence;
1722
1543
  var { Internal: Internal4 } = SchemaExposure;
1723
1544
  var CUSTOMER_OPERATIONS_FACETS = schemaFacets(SchemaContext.CustomerOperations, {
1724
1545
  sdkInput: false
1725
1546
  });
1726
- var IdentitySchema = z9.object({
1727
- external_id: z9.string().min(1).meta(Pii2),
1728
- traits: z9.record(z9.string(), z9.unknown()).default({}).meta(Pii2),
1729
- plan_id: z9.string().optional().meta(Unrestricted6)
1547
+ var IdentitySchema = z8.object({
1548
+ external_id: z8.string().min(1).meta(Pii),
1549
+ traits: z8.record(z8.string(), z8.unknown()).default({}).meta(Pii),
1550
+ plan_id: z8.string().optional().meta(Unrestricted5)
1730
1551
  }).meta(
1731
1552
  {
1732
1553
  id: "Identity",
1733
- "x-revturbine-schema-persistence": Persisted6,
1554
+ "x-revturbine-schema-persistence": Persisted5,
1734
1555
  "x-revturbine-schema-exposure": Internal4
1735
1556
  }
1736
1557
  );
1558
+ var BillingHealthStatusSchema = z8.enum(["payment_failed", "payment_method_missing"]);
1737
1559
  var CustomerSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
1738
- external_id: z9.string().min(1).meta(Pii2),
1739
- identity: IdentitySchema.meta(Pii2),
1740
- stripe_customer_id: z9.string().optional().meta(Unrestricted6),
1741
- current_plan_id: z9.string().optional().meta(Unrestricted6),
1742
- subscription_status: z9.enum(["active", "past_due", "canceled", "trialing", "unpaid", "none"]).default("none").meta(Unrestricted6),
1743
- status: z9.enum(["active", "churned", "trial", "suspended"]).default("active").meta(Unrestricted6),
1744
- metadata: MetadataField.meta(Unrestricted6)
1560
+ external_id: z8.string().min(1).meta(Pii),
1561
+ identity: IdentitySchema.meta(Pii),
1562
+ stripe_customer_id: z8.string().optional().meta(Unrestricted5),
1563
+ current_plan_id: z8.string().optional().meta(Unrestricted5),
1564
+ subscription_status: z8.enum(["active", "past_due", "canceled", "trialing", "unpaid", "none"]).default("none").meta(Unrestricted5),
1565
+ status: z8.enum(["active", "churned", "trial", "suspended"]).default("active").meta(Unrestricted5),
1566
+ /** Active billing-health problems (plan 156); empty array = healthy. */
1567
+ billing_health_issues: z8.array(BillingHealthStatusSchema).default([]).meta(Unrestricted5),
1568
+ metadata: MetadataField.meta(Unrestricted5)
1745
1569
  }).meta(
1746
1570
  {
1747
1571
  id: "Customer",
1748
- "x-revturbine-schema-persistence": Persisted6,
1572
+ "x-revturbine-schema-persistence": Persisted5,
1749
1573
  "x-revturbine-schema-exposure": Internal4
1750
1574
  }
1751
1575
  );
1752
- var CustomerOverrideDurationSchema = z9.enum([
1576
+ var CustomerOverrideDurationSchema = z8.enum([
1753
1577
  "permanent",
1754
1578
  "for_duration"
1755
1579
  ]).meta(
1756
1580
  {
1757
1581
  id: "CustomerOverrideDuration",
1758
- "x-revturbine-schema-persistence": Transient6,
1582
+ "x-revturbine-schema-persistence": Transient5,
1759
1583
  "x-revturbine-schema-exposure": Internal4
1760
1584
  }
1761
1585
  );
1762
- var CustomerOverrideTypeSchema = z9.enum(["grant_plan", "grant_addon", "grant_entitlement"]).meta(
1763
- { id: "CustomerOverrideType", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": Internal4 }
1586
+ var CustomerOverrideTypeSchema = z8.enum(["grant_plan", "grant_addon", "grant_entitlement"]).meta(
1587
+ { id: "CustomerOverrideType", "x-revturbine-schema-persistence": Transient5, "x-revturbine-schema-exposure": Internal4 }
1764
1588
  );
1765
- var CustomerOverrideStatusSchema = z9.enum(["active", "expired", "revoked"]).meta(
1766
- { id: "CustomerOverrideStatus", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": Internal4 }
1589
+ var CustomerOverrideStatusSchema = z8.enum(["active", "expired", "revoked"]).meta(
1590
+ { id: "CustomerOverrideStatus", "x-revturbine-schema-persistence": Transient5, "x-revturbine-schema-exposure": Internal4 }
1767
1591
  );
1768
1592
  var CustomerOverrideSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
1769
- handle: HandleField.meta({ ...Unrestricted6, readOnly: true }),
1770
- customer_id: z9.string().min(1).meta(Pii2),
1771
- customer_id_list: z9.array(z9.string()).optional().meta(Pii2),
1772
- override_type: CustomerOverrideTypeSchema.meta(Unrestricted6),
1773
- target_id: z9.string().min(1).meta(Unrestricted6),
1774
- value: z9.record(z9.string(), z9.unknown()).default({}).meta(Unrestricted6),
1775
- duration_type: CustomerOverrideDurationSchema.default("permanent").meta(Unrestricted6),
1776
- duration_value: z9.string().optional().meta(Unrestricted6),
1777
- expiry_date: NullableDatetimeField.meta(Unrestricted6),
1778
- status: CustomerOverrideStatusSchema.default("active").meta(Unrestricted6),
1779
- reason: z9.string().max(500).optional().meta(Unrestricted6),
1780
- created_by: z9.string().optional().meta(Unrestricted6)
1593
+ handle: HandleField.meta({ ...Unrestricted5, readOnly: true }),
1594
+ customer_id: z8.string().min(1).meta(Pii),
1595
+ customer_id_list: z8.array(z8.string()).optional().meta(Pii),
1596
+ override_type: CustomerOverrideTypeSchema.meta(Unrestricted5),
1597
+ target_id: z8.string().min(1).meta(Unrestricted5),
1598
+ value: z8.record(z8.string(), z8.unknown()).default({}).meta(Unrestricted5),
1599
+ duration_type: CustomerOverrideDurationSchema.default("permanent").meta(Unrestricted5),
1600
+ duration_value: z8.string().optional().meta(Unrestricted5),
1601
+ expiry_date: NullableDatetimeField.meta(Unrestricted5),
1602
+ status: CustomerOverrideStatusSchema.default("active").meta(Unrestricted5),
1603
+ reason: z8.string().max(500).optional().meta(Unrestricted5),
1604
+ created_by: z8.string().optional().meta(Unrestricted5)
1781
1605
  }).meta(
1782
1606
  {
1783
1607
  id: "CustomerOverride",
1784
- "x-revturbine-schema-persistence": Persisted6,
1608
+ "x-revturbine-schema-persistence": Persisted5,
1785
1609
  "x-revturbine-schema-exposure": Internal4,
1786
1610
  ...CUSTOMER_OPERATIONS_FACETS,
1787
1611
  // KENT-REVIEW (plan 121): defaulted to Bucket 2 on (customer_id, override_type,
@@ -1805,7 +1629,7 @@ var customerPaths = {
1805
1629
  "/api/customers/{customerId}": {
1806
1630
  get: operation({
1807
1631
  operationId: "getCustomer",
1808
- requestParams: { path: z9.object({ customerId: z9.string() }) },
1632
+ requestParams: { path: z8.object({ customerId: z8.string() }) },
1809
1633
  summary: "Get customer by ID",
1810
1634
  tags: ["customers"],
1811
1635
  responses: { "200": { description: "Customer", content: { "application/json": { schema: CustomerSchema } } } },
@@ -1833,7 +1657,7 @@ var customerPaths = {
1833
1657
  "/api/customer-overrides/{overrideId}": {
1834
1658
  get: operation({
1835
1659
  operationId: "getCustomerOverride",
1836
- requestParams: { path: z9.object({ overrideId: z9.string() }) },
1660
+ requestParams: { path: z8.object({ overrideId: z8.string() }) },
1837
1661
  summary: "Get customer override",
1838
1662
  tags: ["customers"],
1839
1663
  responses: { "200": { description: "Override", content: { "application/json": { schema: CustomerOverrideSchema } } } },
@@ -1841,7 +1665,7 @@ var customerPaths = {
1841
1665
  }),
1842
1666
  patch: operation({
1843
1667
  operationId: "updateCustomerOverride",
1844
- requestParams: { path: z9.object({ overrideId: z9.string() }) },
1668
+ requestParams: { path: z8.object({ overrideId: z8.string() }) },
1845
1669
  summary: "Update customer override",
1846
1670
  tags: ["customers"],
1847
1671
  requestBody: { required: true, content: { "application/json": { schema: CustomerOverrideSchema.partial() } } },
@@ -1850,7 +1674,7 @@ var customerPaths = {
1850
1674
  }),
1851
1675
  delete: operation({
1852
1676
  operationId: "deleteCustomerOverride",
1853
- requestParams: { path: z9.object({ overrideId: z9.string() }) },
1677
+ requestParams: { path: z8.object({ overrideId: z8.string() }) },
1854
1678
  summary: "Delete customer override",
1855
1679
  tags: ["customers"],
1856
1680
  responses: { "204": { description: "Deleted" } },
@@ -1860,7 +1684,7 @@ var customerPaths = {
1860
1684
  "/api/customer-overrides/{overrideId}/revoke": {
1861
1685
  post: operation({
1862
1686
  operationId: "revokeCustomerOverride",
1863
- requestParams: { path: z9.object({ overrideId: z9.string() }) },
1687
+ requestParams: { path: z8.object({ overrideId: z8.string() }) },
1864
1688
  summary: "Revoke an active customer override",
1865
1689
  tags: ["customers"],
1866
1690
  responses: { "200": { description: "Revoked", content: { "application/json": { schema: CustomerOverrideSchema } } } },
@@ -1870,28 +1694,270 @@ var customerPaths = {
1870
1694
  "/api/customer-overrides/{overrideId}/duplicate": {
1871
1695
  post: operation({
1872
1696
  operationId: "duplicateCustomerOverride",
1873
- requestParams: { path: z9.object({ overrideId: z9.string() }) },
1697
+ requestParams: { path: z8.object({ overrideId: z8.string() }) },
1874
1698
  summary: "Duplicate customer override for another customer",
1875
1699
  tags: ["customers"],
1876
- requestBody: { required: true, content: { "application/json": { schema: z9.object({ customer_id: z9.string() }) } } },
1700
+ requestBody: { required: true, content: { "application/json": { schema: z8.object({ customer_id: z8.string() }) } } },
1877
1701
  responses: { "201": { description: "Duplicated", content: { "application/json": { schema: CustomerOverrideSchema } } } },
1878
1702
  "x-revturbine-operation": { exposure: "internal", resource: "customer-overrides", persistence: { table: "customerOverrides", mode: "create" } }
1879
1703
  })
1880
1704
  }
1881
1705
  };
1706
+ var { Unrestricted: Unrestricted6, Pii: Pii2, Financial: Financial2 } = DataClassification;
1707
+ var { Persisted: Persisted6, Transient: Transient6 } = SchemaPersistence;
1708
+ var { External: External5, Internal: Internal5 } = SchemaExposure;
1709
+ var UserTrialStatusSchema = z9.object({
1710
+ in_trial: z9.boolean().meta(Unrestricted6),
1711
+ trial_type: z9.string().optional().meta(Unrestricted6),
1712
+ plan_handle: z9.string().optional().meta(Unrestricted6),
1713
+ // 'converted' reflects a server-side analytic-event transition
1714
+ // (typically a Stripe webhook like `customer.subscription.created`
1715
+ // or `invoice.payment_succeeded` against a trialing subscription)
1716
+ // that the control plane processes to flip TrialInstance.status.
1717
+ // The SDK reads this state from the decision-API response — it does
1718
+ // NOT derive 'converted' client-side. trial_lifecycle.v1 rules
1719
+ // matching on 'trial_converted' fire while the user's status carries
1720
+ // this value, enabling conversion-celebration / receipt placements.
1721
+ state: z9.enum(["active", "running_out", "expired", "converted", "none"]).optional().meta(Unrestricted6),
1722
+ /**
1723
+ * Trial limit model — mirrors the rule's `trial_limit_type`. The
1724
+ * SDK uses this to decide which numeric fields below to surface;
1725
+ * the placement-resolver gates `trial_ending(days_before_end)`
1726
+ * only when `trial_limit_type === 'time'`.
1727
+ */
1728
+ trial_limit_type: z9.enum(["time", "usage"]).optional().meta(Unrestricted6),
1729
+ /**
1730
+ * Universal progress metric, 0..100. Computed by
1731
+ * `deriveLocalTrialStatusFromInstance` from elapsed days
1732
+ * (time-based) or consumed/limit (usage-based). Trial rule
1733
+ * modules + placement-resolver supersession consume this field
1734
+ * so they don't have to branch on the limit type.
1735
+ */
1736
+ progress_percent: z9.number().min(0).max(100).optional().meta(Unrestricted6),
1737
+ // Time-based numeric fields. Populated when trial_limit_type='time'.
1738
+ day_number: z9.number().int().min(0).optional().meta(Unrestricted6),
1739
+ days_remaining: z9.number().int().min(0).optional().meta(Unrestricted6),
1740
+ // Usage-based numeric fields. Populated when trial_limit_type='usage'.
1741
+ usage_entitlement_handle: z9.string().optional().meta(Unrestricted6),
1742
+ usage_consumed: z9.number().int().min(0).optional().meta(Unrestricted6),
1743
+ usage_remaining: z9.number().int().min(0).optional().meta(Unrestricted6),
1744
+ usage_limit: z9.number().int().min(0).optional().meta(Unrestricted6)
1745
+ }).meta(
1746
+ { id: "UserTrialStatus", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": External5 }
1747
+ );
1748
+ var UserUsageEntrySchema = z9.object({
1749
+ entitlement_handle: z9.string().min(1).meta(Unrestricted6),
1750
+ unit: z9.string().min(1).meta(Unrestricted6),
1751
+ amount: z9.number().min(0).meta(Unrestricted6),
1752
+ limit: z9.number().min(0).optional().meta(Unrestricted6),
1753
+ reset_date: z9.string().optional().meta(Unrestricted6)
1754
+ }).meta(
1755
+ { id: "UserUsageEntry", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": External5 }
1756
+ );
1757
+ var UserPlanContextSchema = z9.object({
1758
+ id: z9.string().min(1).meta(Unrestricted6),
1759
+ name: z9.string().min(1).meta(Unrestricted6),
1760
+ price: z9.string().optional().meta(Unrestricted6),
1761
+ billing_period: z9.enum(["monthly", "annual", "none"]).optional().meta(Unrestricted6)
1762
+ }).meta(
1763
+ { id: "UserPlanContext", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": External5 }
1764
+ );
1765
+ var UserInstanceContextSchema = z9.object({
1766
+ product_instance_id: z9.string().min(1).meta(Unrestricted6),
1767
+ user_id: z9.string().min(1).meta(Pii2),
1768
+ plan: UserPlanContextSchema.optional().meta(Unrestricted6),
1769
+ /** Usage entries for this instance, keyed by entitlement handle. */
1770
+ usage: z9.record(z9.string(), UserUsageEntrySchema).default({}).meta(Unrestricted6),
1771
+ trial: UserTrialStatusSchema.optional().meta(Unrestricted6),
1772
+ /** Entitlements resolved at this instance level, keyed by handle. */
1773
+ entitlements: z9.record(z9.string(), z9.union([z9.boolean(), EntitlementGrantSchema])).default({}).meta(Unrestricted6)
1774
+ }).meta(
1775
+ {
1776
+ id: "UserInstanceContext",
1777
+ "x-revturbine-schema-persistence": Persisted6,
1778
+ "x-revturbine-schema-exposure": External5
1779
+ }
1780
+ );
1781
+ var UserContextSchema = IdField.merge(TenantIdField).merge(TimestampFields).extend({
1782
+ user_id: z9.string().min(1).meta(Pii2),
1783
+ account_id: z9.string().min(1).nullable().optional().meta(Pii2),
1784
+ email: z9.string().email().nullable().optional().meta(Pii2),
1785
+ /** Optional email classification (e.g. `business`, `personal`). */
1786
+ email_type: z9.string().optional().meta(Unrestricted6),
1787
+ plan: UserPlanContextSchema.optional().meta(Unrestricted6),
1788
+ /** Aggregate usage entries across all instances, keyed by handle. */
1789
+ usage: z9.record(z9.string(), UserUsageEntrySchema).default({}).meta(Unrestricted6),
1790
+ trial: UserTrialStatusSchema.optional().meta(Unrestricted6),
1791
+ /**
1792
+ * Billing-recovery signals (account-level). `payment_failed` reflects a
1793
+ * hard payment failure (e.g. Stripe `invoice.payment_failed`);
1794
+ * `payment_at_risk` an expiring / missing-backup payment method. They
1795
+ * drive the Retention `qualifier` placement triggers
1796
+ * (placement-studio-ui.md §3.7) — the SDK surfaces them onto the
1797
+ * PlanProvider state the placement resolver reads. Omitted for users in
1798
+ * good standing; a qualifier gate reads `=== true`, so an absent signal
1799
+ * never fires the recovery placement.
1800
+ */
1801
+ payment_failed: z9.boolean().optional().meta(Unrestricted6),
1802
+ payment_at_risk: z9.boolean().optional().meta(Unrestricted6),
1803
+ /**
1804
+ * The user's current tier per `capability_tier` entitlement, keyed by
1805
+ * entitlement handle → tier handle (plan 138 TASK-4). Drives the
1806
+ * `entitlement_gate.tier_threshold` placement trigger: the SDK surfaces
1807
+ * this onto the EntitlementProvider state, and the resolver ranks the
1808
+ * current tier against the entitlement's ordered ladder. Omitted for a
1809
+ * user holding no tier (ranks below every threshold).
1810
+ */
1811
+ tiers: z9.record(z9.string(), z9.string()).optional().meta(Unrestricted6),
1812
+ /** Account-level entitlements, keyed by handle. */
1813
+ entitlements: z9.record(z9.string(), z9.union([z9.boolean(), EntitlementGrantSchema])).default({}).meta(Unrestricted6),
1814
+ /** Per-instance breakdowns when the account has multiple product instances. */
1815
+ instances: z9.array(UserInstanceContextSchema).optional().meta(Unrestricted6),
1816
+ /** Customer-defined fields: role, app-level permissions, display prefs. */
1817
+ custom: z9.record(z9.string(), z9.union([z9.string(), z9.number(), z9.boolean(), z9.null()])).default({}).meta(Pii2),
1818
+ /**
1819
+ * Transient personalization token map.
1820
+ *
1821
+ * Holds SDK-derived tokens (plan_name, usage_current, etc.) merged with
1822
+ * app-provided tokens. Not persisted to the backend — rebuilt on each
1823
+ * SDK session from context + exported config.
1824
+ */
1825
+ personalization: z9.record(z9.string(), z9.union([z9.string(), z9.number()])).default({}).meta({ ...Unrestricted6, "x-revturbine-schema-persistence": Transient6 }),
1826
+ // ── Derived-entitlement cache (plan 74 REQ-12/REQ-13) ──────────────
1827
+ // `entitlements` above is the rule-evaluated projection — a CACHE, not
1828
+ // source of truth. These stamps record what it was computed against so a
1829
+ // read can detect staleness: recompute when the active config version
1830
+ // moved on OR the context hash changed.
1831
+ /** Active config version (activated change-set id / compiled-bundle stamp) the cache was computed against. */
1832
+ derived_config_version: z9.string().nullable().optional().meta(Unrestricted6),
1833
+ /** Deterministic `computeUserContextHash` of the inputs the cache was computed from (REQ-13 ETag value). */
1834
+ context_hash: z9.string().nullable().optional().meta(Unrestricted6),
1835
+ /** When the cached entitlements were last (re)computed. */
1836
+ derived_computed_at: NullableDatetimeField.meta(Unrestricted6)
1837
+ }).meta(
1838
+ { id: "UserContext", "x-revturbine-schema-persistence": Persisted6, "x-revturbine-schema-exposure": External5 }
1839
+ );
1840
+ var ClientContextTrialSchema = z9.object({
1841
+ status: z9.enum(["active", "running_out", "expired", "converted", "none"]).meta({ ...Unrestricted6, ...ClientSafe }),
1842
+ days_remaining: z9.number().int().min(0).optional().meta({ ...Unrestricted6, ...ClientSafe }),
1843
+ ends_at: z9.string().optional().meta({ ...Unrestricted6, ...ClientSafe })
1844
+ }).meta(
1845
+ { id: "ClientContextTrial", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": Internal5 }
1846
+ );
1847
+ var ClientContextBillingSchema = z9.object({
1848
+ /** Coarse, browser-safe billing-health signal (the only billing field exposed). */
1849
+ health: z9.enum(["ok", "attention_required"]).optional().meta({ ...Unrestricted6, ...ClientSafe }),
1850
+ /** decision_only — drives retention placements server-side; never returned to the browser. */
1851
+ failed_payment_reason: z9.string().optional().meta({ ...Financial2, ...DecisionOnly }),
1852
+ /**
1853
+ * decision_only — the raw billing-health issue codes (plan 156). The coarse
1854
+ * `health` above is derived from whether this is non-empty; these raw codes
1855
+ * may drive server-side Playbook decisions but are stripped by the exposure
1856
+ * filter and never returned to the browser.
1857
+ */
1858
+ issues: z9.array(BillingHealthStatusSchema).optional().meta({ ...Financial2, ...DecisionOnly }),
1859
+ /** server_only — raw provider identifier; never exposed. */
1860
+ provider_subscription_id: z9.string().optional().meta({ ...Financial2, ...ServerOnly })
1861
+ }).meta(
1862
+ { id: "ClientContextBilling", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": Internal5 }
1863
+ );
1864
+ var ClientContextCapabilitiesSchema = z9.object({
1865
+ can_upgrade: z9.boolean().optional().meta({ ...Unrestricted6, ...ClientSafe }),
1866
+ can_manage_billing: z9.boolean().optional().meta({ ...Unrestricted6, ...ClientSafe })
1867
+ }).meta(
1868
+ { id: "ClientContextCapabilities", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": Internal5 }
1869
+ );
1870
+ var ClientContextPlanSchema = z9.object({
1871
+ /** The customer's current plan handle (`plans.unique_handle`). */
1872
+ handle: z9.string().min(1).optional().meta({ ...Unrestricted6, ...ClientSafe }),
1873
+ /**
1874
+ * The plan's display name, resolved server-side from the plan record so
1875
+ * client UI can render it without a Playbook lookup (plan 179 TASK-1 —
1876
+ * Q-2 ruling: `{ handle, name }`). Plan names are already client-visible
1877
+ * in every Playbook; no new exposure.
1878
+ */
1879
+ name: z9.string().min(1).optional().meta({ ...Unrestricted6, ...ClientSafe })
1880
+ }).meta(
1881
+ { id: "ClientContextPlan", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": Internal5 }
1882
+ );
1883
+ var ClientContextSchema = z9.object({
1884
+ /** The end-user subject the client token was minted for (carried by the token, not the request). */
1885
+ subject: z9.string().min(1).meta({ ...Unrestricted6, ...ClientSafe }),
1886
+ /** Opaque version stamp of the underlying context snapshot. */
1887
+ context_version: z9.string().optional().meta({ ...Unrestricted6, ...ClientSafe }),
1888
+ trial: ClientContextTrialSchema.optional().meta({ ...Unrestricted6, ...ClientSafe }),
1889
+ billing: ClientContextBillingSchema.optional().meta({ ...Unrestricted6, ...ClientSafe }),
1890
+ plan: ClientContextPlanSchema.optional().meta({ ...Unrestricted6, ...ClientSafe }),
1891
+ capabilities: ClientContextCapabilitiesSchema.optional().meta({ ...Unrestricted6, ...ClientSafe })
1892
+ }).meta(
1893
+ { id: "ClientContext", "x-revturbine-schema-persistence": Transient6, "x-revturbine-schema-exposure": Internal5 }
1894
+ );
1895
+ var userContextPaths = {
1896
+ "/api/user-contexts": {
1897
+ get: operation({
1898
+ operationId: "listUserContexts",
1899
+ requestParams: { query: ListQueryParamsSchema },
1900
+ summary: "List user contexts",
1901
+ tags: ["users"],
1902
+ responses: { "200": { description: "User context list", content: { "application/json": { schema: ListEnvelope(UserContextSchema) } } } },
1903
+ "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "list" } }
1904
+ }),
1905
+ // Upsert by (tenant_id, user_id): the SDK identify/setUserContext path
1906
+ // writes the persisted context. The collection POST is the create-or-update
1907
+ // entry point — the route resolves the existing row by (tenant_id, user_id)
1908
+ // and applies an idempotent upsert (server-side, plan 74 TASK-4).
1909
+ post: operation({
1910
+ operationId: "createUserContext",
1911
+ summary: "Create or upsert a user context",
1912
+ tags: ["users"],
1913
+ requestBody: { required: true, content: { "application/json": { schema: UserContextSchema } } },
1914
+ responses: { "201": { description: "Created", content: { "application/json": { schema: UserContextSchema } } } },
1915
+ "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "create", uniqueBy: ["tenant_id", "user_id"] } }
1916
+ })
1917
+ },
1918
+ "/api/user-contexts/{userContextId}": {
1919
+ get: operation({
1920
+ operationId: "getUserContext",
1921
+ requestParams: { path: z9.object({ userContextId: z9.string() }) },
1922
+ summary: "Get user context",
1923
+ tags: ["users"],
1924
+ responses: { "200": { description: "User context", content: { "application/json": { schema: UserContextSchema } } } },
1925
+ "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "get" } }
1926
+ }),
1927
+ patch: operation({
1928
+ operationId: "updateUserContext",
1929
+ requestParams: { path: z9.object({ userContextId: z9.string() }) },
1930
+ summary: "Update a user context",
1931
+ tags: ["users"],
1932
+ requestBody: { required: true, content: { "application/json": { schema: UserContextSchema.partial() } } },
1933
+ responses: { "200": { description: "Updated", content: { "application/json": { schema: UserContextSchema } } } },
1934
+ "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "update" } }
1935
+ }),
1936
+ // Delete path ships in v1 (plan 74 Q-1): a user context can be removed on
1937
+ // request now; full by-email DSR tooling remains deferred (sdk.md §8).
1938
+ delete: operation({
1939
+ operationId: "deleteUserContext",
1940
+ requestParams: { path: z9.object({ userContextId: z9.string() }) },
1941
+ summary: "Delete a user context",
1942
+ tags: ["users"],
1943
+ responses: { "204": { description: "Deleted" } },
1944
+ "x-revturbine-operation": { exposure: "internal", resource: "user-contexts", persistence: { table: "userContexts", mode: "delete" } }
1945
+ })
1946
+ }
1947
+ };
1882
1948
  var { Unrestricted: Unrestricted7 } = DataClassification;
1883
1949
  var { Persisted: Persisted7, Transient: Transient7 } = SchemaPersistence;
1884
- var { Internal: Internal5 } = SchemaExposure;
1950
+ var { Internal: Internal6 } = SchemaExposure;
1885
1951
  var PLAYBOOK_SDK_FACETS4 = schemaFacets(SchemaContext.Playbook, { sdkInput: true });
1886
1952
  var PENDING_PLAYBOOK_SDK_FACETS = schemaFacets(SchemaContext.Playbook, {
1887
1953
  inConfig: false,
1888
1954
  sdkInput: true
1889
1955
  });
1890
1956
  var DimensionCategorySchema = z10.enum(["default", "custom"]).meta(
1891
- { id: "DimensionCategory", "x-revturbine-schema-persistence": Transient7, "x-revturbine-schema-exposure": Internal5 }
1957
+ { id: "DimensionCategory", "x-revturbine-schema-persistence": Transient7, "x-revturbine-schema-exposure": Internal6 }
1892
1958
  );
1893
1959
  var DimensionSourceTypeSchema = z10.enum(["system", "sdk_trait", "sdk_trait_enum", "cdp_property", "manual_list"]).meta(
1894
- { id: "DimensionSourceType", "x-revturbine-schema-persistence": Transient7, "x-revturbine-schema-exposure": Internal5 }
1960
+ { id: "DimensionSourceType", "x-revturbine-schema-persistence": Transient7, "x-revturbine-schema-exposure": Internal6 }
1895
1961
  );
1896
1962
  var SegmentDimensionSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
1897
1963
  anchor_id: z10.string().min(1).meta({ ...Unrestricted7, readOnly: true }),
@@ -1909,7 +1975,7 @@ var SegmentDimensionSchema = IdField.merge(TimestampFields).merge(TenantIdField)
1909
1975
  {
1910
1976
  id: "SegmentDimension",
1911
1977
  "x-revturbine-schema-persistence": Persisted7,
1912
- "x-revturbine-schema-exposure": Internal5,
1978
+ "x-revturbine-schema-exposure": Internal6,
1913
1979
  ...PENDING_PLAYBOOK_SDK_FACETS,
1914
1980
  ...namedIdentity()
1915
1981
  }
@@ -1927,7 +1993,7 @@ var SegmentValueSchema = IdField.merge(TimestampFields).merge(TenantIdField).mer
1927
1993
  {
1928
1994
  id: "SegmentValue",
1929
1995
  "x-revturbine-schema-persistence": Persisted7,
1930
- "x-revturbine-schema-exposure": Internal5,
1996
+ "x-revturbine-schema-exposure": Internal6,
1931
1997
  ...PENDING_PLAYBOOK_SDK_FACETS,
1932
1998
  ...namedIdentity()
1933
1999
  }
@@ -1946,7 +2012,7 @@ var SegmentSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(An
1946
2012
  {
1947
2013
  id: "Segment",
1948
2014
  "x-revturbine-schema-persistence": Persisted7,
1949
- "x-revturbine-schema-exposure": Internal5,
2015
+ "x-revturbine-schema-exposure": Internal6,
1950
2016
  ...PLAYBOOK_SDK_FACETS4,
1951
2017
  ...namedIdentity()
1952
2018
  }
@@ -2280,7 +2346,7 @@ var contentPaths = {
2280
2346
  };
2281
2347
  var { Unrestricted: Unrestricted9, Pii: Pii3 } = DataClassification;
2282
2348
  var { Persisted: Persisted9, Transient: Transient9 } = SchemaPersistence;
2283
- var { Internal: Internal6, External: External7 } = SchemaExposure;
2349
+ var { Internal: Internal7, External: External7 } = SchemaExposure;
2284
2350
  var BRANDING_FACETS = schemaFacets(SchemaContext.Branding, { sdkInput: false });
2285
2351
  var ThemeSchema = z12.object({
2286
2352
  id: z12.string().min(1).meta({ ...Unrestricted9, readOnly: true }),
@@ -2303,7 +2369,7 @@ var UiPreferenceSchema = IdField.merge(TimestampFields).extend({
2303
2369
  {
2304
2370
  id: "UiPreference",
2305
2371
  "x-revturbine-schema-persistence": Persisted9,
2306
- "x-revturbine-schema-exposure": Internal6
2372
+ "x-revturbine-schema-exposure": Internal7
2307
2373
  }
2308
2374
  );
2309
2375
  var uiPreferencePaths = {
@@ -2347,15 +2413,15 @@ var uiPreferencePaths = {
2347
2413
  })
2348
2414
  }
2349
2415
  };
2350
- var { Unrestricted: Unrestricted10, Financial: Financial2 } = DataClassification;
2416
+ var { Unrestricted: Unrestricted10, Financial: Financial3 } = DataClassification;
2351
2417
  var { Persisted: Persisted10, Transient: Transient10 } = SchemaPersistence;
2352
- var { External: External8, Internal: Internal7 } = SchemaExposure;
2418
+ var { External: External8, Internal: Internal8 } = SchemaExposure;
2353
2419
  var CohortMonthSchema = z13.object({
2354
2420
  month: z13.string().meta(Unrestricted10),
2355
2421
  cohort_size: z13.number().int().min(0).meta(Unrestricted10),
2356
2422
  retained: z13.number().int().min(0).meta(Unrestricted10),
2357
2423
  retention_rate: z13.number().min(0).max(1).meta(Unrestricted10),
2358
- revenue_cents: z13.number().int().min(0).meta(Financial2)
2424
+ revenue_cents: z13.number().int().min(0).meta(Financial3)
2359
2425
  }).meta(
2360
2426
  { id: "CohortMonth", "x-revturbine-schema-persistence": Transient10, "x-revturbine-schema-exposure": External8 }
2361
2427
  );
@@ -2376,26 +2442,26 @@ var PlacementPerformanceRowSchema = z13.object({
2376
2442
  conversions: z13.number().int().min(0).meta(Unrestricted10),
2377
2443
  ctr: z13.number().min(0).meta(Unrestricted10),
2378
2444
  conversion_rate: z13.number().min(0).meta(Unrestricted10),
2379
- revenue_cents: z13.number().int().min(0).meta(Financial2)
2445
+ revenue_cents: z13.number().int().min(0).meta(Financial3)
2380
2446
  }).meta(
2381
2447
  { id: "PlacementPerformanceRow", "x-revturbine-schema-persistence": Transient10, "x-revturbine-schema-exposure": External8 }
2382
2448
  );
2383
2449
  var RevenueMetricSchema = z13.object({
2384
2450
  date: z13.string().meta(Unrestricted10),
2385
- mrr_cents: z13.number().int().min(0).meta(Financial2),
2386
- arr_cents: z13.number().int().min(0).meta(Financial2),
2387
- new_mrr_cents: z13.number().int().min(0).meta(Financial2),
2388
- churned_mrr_cents: z13.number().int().min(0).meta(Financial2),
2389
- expansion_mrr_cents: z13.number().int().min(0).meta(Financial2),
2390
- net_new_mrr_cents: z13.number().int().meta(Financial2)
2451
+ mrr_cents: z13.number().int().min(0).meta(Financial3),
2452
+ arr_cents: z13.number().int().min(0).meta(Financial3),
2453
+ new_mrr_cents: z13.number().int().min(0).meta(Financial3),
2454
+ churned_mrr_cents: z13.number().int().min(0).meta(Financial3),
2455
+ expansion_mrr_cents: z13.number().int().min(0).meta(Financial3),
2456
+ net_new_mrr_cents: z13.number().int().meta(Financial3)
2391
2457
  }).meta(
2392
2458
  { id: "RevenueMetric", "x-revturbine-schema-persistence": Transient10, "x-revturbine-schema-exposure": External8 }
2393
2459
  );
2394
2460
  var KpiAggregateSchema = z13.object({
2395
2461
  metric_key: z13.string().min(1).meta(Unrestricted10),
2396
2462
  label: z13.string().meta(Unrestricted10),
2397
- current_value: z13.number().meta(Financial2),
2398
- previous_value: z13.number().nullable().default(null).meta(Financial2),
2463
+ current_value: z13.number().meta(Financial3),
2464
+ previous_value: z13.number().nullable().default(null).meta(Financial3),
2399
2465
  change_percent: z13.number().nullable().default(null).meta(Unrestricted10),
2400
2466
  period: z13.string().meta(Unrestricted10),
2401
2467
  unit: z13.enum(["count", "cents", "percent", "ratio", "seconds"]).default("count").meta(Unrestricted10)
@@ -2415,7 +2481,7 @@ var DriftReportSchema = IdField.merge(TimestampFields).merge(TenantIdField).exte
2415
2481
  resolved_at: NullableDatetimeField.meta(Unrestricted10),
2416
2482
  metadata: MetadataField.meta(Unrestricted10)
2417
2483
  }).meta(
2418
- { id: "DriftReport", "x-revturbine-schema-persistence": Persisted10, "x-revturbine-schema-exposure": Internal7 }
2484
+ { id: "DriftReport", "x-revturbine-schema-persistence": Persisted10, "x-revturbine-schema-exposure": Internal8 }
2419
2485
  );
2420
2486
  var AlertSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
2421
2487
  alert_type: z13.enum(["usage_threshold", "revenue_drop", "conversion_drop", "experiment_significance", "drift_detected", "custom"]).meta(Unrestricted10),
@@ -2429,7 +2495,7 @@ var AlertSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
2429
2495
  acknowledged_by: z13.string().nullable().default(null).meta(Unrestricted10),
2430
2496
  metadata: MetadataField.meta(Unrestricted10)
2431
2497
  }).meta(
2432
- { id: "Alert", "x-revturbine-schema-persistence": Persisted10, "x-revturbine-schema-exposure": Internal7 }
2498
+ { id: "Alert", "x-revturbine-schema-persistence": Persisted10, "x-revturbine-schema-exposure": Internal8 }
2433
2499
  );
2434
2500
  var analyticsPaths = {
2435
2501
  "/api/analytics/kpis": {
@@ -2525,7 +2591,7 @@ var analyticsPaths = {
2525
2591
  };
2526
2592
  var { Unrestricted: Unrestricted11, Pii: Pii4 } = DataClassification;
2527
2593
  var { Persisted: Persisted11, Transient: Transient11 } = SchemaPersistence;
2528
- var { Internal: Internal8, External: External9 } = SchemaExposure;
2594
+ var { Internal: Internal9, External: External9 } = SchemaExposure;
2529
2595
  var EventSourceSchema = z14.enum(["clickstream", "telemetry", "sdk", "workflow", "system"]).meta(
2530
2596
  {
2531
2597
  id: "EventSource",
@@ -2547,7 +2613,7 @@ var EventEnvelopeSchema = IdField.extend({
2547
2613
  {
2548
2614
  id: "EventEnvelope",
2549
2615
  "x-revturbine-schema-persistence": Transient11,
2550
- "x-revturbine-schema-exposure": Internal8
2616
+ "x-revturbine-schema-exposure": Internal9
2551
2617
  }
2552
2618
  );
2553
2619
  var IngestedEventSchema = EventEnvelopeSchema.extend({
@@ -2556,7 +2622,7 @@ var IngestedEventSchema = EventEnvelopeSchema.extend({
2556
2622
  {
2557
2623
  id: "IngestedEvent",
2558
2624
  "x-revturbine-schema-persistence": Persisted11,
2559
- "x-revturbine-schema-exposure": Internal8
2625
+ "x-revturbine-schema-exposure": Internal9
2560
2626
  }
2561
2627
  );
2562
2628
  var EventIngestBatchSchema = z14.array(
@@ -2577,7 +2643,7 @@ var EventIngestBatchSchema = z14.array(
2577
2643
  {
2578
2644
  id: "EventIngestBatch",
2579
2645
  "x-revturbine-schema-persistence": Transient11,
2580
- "x-revturbine-schema-exposure": Internal8
2646
+ "x-revturbine-schema-exposure": Internal9
2581
2647
  }
2582
2648
  );
2583
2649
  var TreatmentInteractionTypeSchema = z14.enum([
@@ -2606,6 +2672,12 @@ var TreatmentInteractionInputSchema = z14.object({
2606
2672
  payload_id: z14.string().min(1).optional().meta(Unrestricted11),
2607
2673
  interaction_type: TreatmentInteractionTypeSchema.meta(Unrestricted11),
2608
2674
  interaction_at: z14.string().datetime().optional().meta(Unrestricted11),
2675
+ /**
2676
+ * Caller-declared test traffic (plan 164) — mirrors `TrackEvent.test` so
2677
+ * the presentation/interaction feed (the dashboard denominators) carries
2678
+ * the same default-excluded, `include_test`-toggleable dimension.
2679
+ */
2680
+ test: z14.boolean().optional().meta(Unrestricted11),
2609
2681
  metadata: z14.record(z14.string(), z14.unknown()).optional().meta(Unrestricted11)
2610
2682
  }).meta(
2611
2683
  {
@@ -2754,21 +2826,21 @@ var EventSearchParamsSchema = z14.object({
2754
2826
  {
2755
2827
  id: "EventSearchParams",
2756
2828
  "x-revturbine-schema-persistence": Transient11,
2757
- "x-revturbine-schema-exposure": Internal8
2829
+ "x-revturbine-schema-exposure": Internal9
2758
2830
  }
2759
2831
  );
2760
2832
  var WebhookEventSourceSchema = z14.enum(["stripe", "apple", "google"]).meta(
2761
2833
  {
2762
2834
  id: "WebhookEventSource",
2763
2835
  "x-revturbine-schema-persistence": Transient11,
2764
- "x-revturbine-schema-exposure": Internal8
2836
+ "x-revturbine-schema-exposure": Internal9
2765
2837
  }
2766
2838
  );
2767
2839
  var WebhookEventStatusSchema = z14.enum(["processed", "failed", "skipped"]).meta(
2768
2840
  {
2769
2841
  id: "WebhookEventStatus",
2770
2842
  "x-revturbine-schema-persistence": Transient11,
2771
- "x-revturbine-schema-exposure": Internal8
2843
+ "x-revturbine-schema-exposure": Internal9
2772
2844
  }
2773
2845
  );
2774
2846
  var WebhookEventLogSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
@@ -2783,7 +2855,7 @@ var WebhookEventLogSchema = IdField.merge(TimestampFields).merge(TenantIdField).
2783
2855
  {
2784
2856
  id: "WebhookEventLog",
2785
2857
  "x-revturbine-schema-persistence": Persisted11,
2786
- "x-revturbine-schema-exposure": Internal8
2858
+ "x-revturbine-schema-exposure": Internal9
2787
2859
  }
2788
2860
  );
2789
2861
  var EventIngestResponseSchema = z14.object({
@@ -2792,7 +2864,7 @@ var EventIngestResponseSchema = z14.object({
2792
2864
  {
2793
2865
  id: "null",
2794
2866
  "x-revturbine-schema-persistence": Transient11,
2795
- "x-revturbine-schema-exposure": Internal8
2867
+ "x-revturbine-schema-exposure": Internal9
2796
2868
  }
2797
2869
  );
2798
2870
  var MAX_TRACK_EVENTS_PER_BATCH = 500;
@@ -2837,7 +2909,16 @@ var TrackEventSchema = z14.object({
2837
2909
  /** Immutable Playbook version that produced the experience. The field that makes a past decision reproducible. */
2838
2910
  playbook_version: z14.string().nullable().optional().meta(Unrestricted11),
2839
2911
  /** Correlates every event caused by one decision — a join key, not a group-by. */
2840
- decision_id: z14.string().nullable().optional().meta(Unrestricted11)
2912
+ decision_id: z14.string().nullable().optional().meta(Unrestricted11),
2913
+ /**
2914
+ * Caller-declared test traffic (plan 164): set from the SDK's `test` init
2915
+ * option, stamped on every emitted event. Analytics pipes exclude
2916
+ * `test = true` rows from denominators/rollups by default, with an
2917
+ * `include_test` pipe parameter as the opt-in toggle. Distinct from the
2918
+ * placement "Test Mode" (plan 08c), which is a server-decided per-user
2919
+ * flag on DECISIONING responses — this one marks EMITTED events.
2920
+ */
2921
+ test: z14.boolean().optional().meta(Unrestricted11)
2841
2922
  }).meta(
2842
2923
  {
2843
2924
  id: "TrackEvent",
@@ -2855,7 +2936,7 @@ var TrackIngestBatchSchema = z14.object({
2855
2936
  }
2856
2937
  );
2857
2938
  var MAX_SDK_META_EVENTS_PER_BATCH = 10;
2858
- var SdkMetaEventTypeSchema = z14.enum(["sdk_init", "sdk_error", "sdk_validation_warning"]).meta(
2939
+ var SdkMetaEventTypeSchema = z14.enum(["sdk_init", "sdk_error", "sdk_validation_warning", "resolution_failure"]).meta(
2859
2940
  {
2860
2941
  id: "SdkMetaEventType",
2861
2942
  "x-revturbine-schema-persistence": Transient11,
@@ -2893,7 +2974,19 @@ var SdkMetaEventSchema = z14.object({
2893
2974
  // Present for sdk_init; config-shape counts only, no user context (REQ-6).
2894
2975
  config_shape: SdkConfigShapeSchema.optional().meta(Unrestricted11),
2895
2976
  // Short non-PII diagnostic for sdk_error / sdk_validation_warning.
2896
- message: z14.string().max(500).optional().meta(Unrestricted11)
2977
+ message: z14.string().max(500).optional().meta(Unrestricted11),
2978
+ // Diagnostic fields for `resolution_failure` (plan 144 TASK-20; absorbed
2979
+ // plan 124 REQ-5/AC-6 — its Q-1 allow-list, append-only). Every value is
2980
+ // an AUTHOR-DEFINED handle or a closed reason code — never user-supplied
2981
+ // free text; `message` above remains the only prose field and stays
2982
+ // length-capped. Emitted from the SDK's fallback/deny sites so a
2983
+ // placement that silently resolves to nothing becomes observable.
2984
+ reason: z14.string().min(1).max(64).optional().meta(Unrestricted11),
2985
+ placement_handle: z14.string().min(1).max(64).optional().meta(Unrestricted11),
2986
+ slot_handle: z14.string().min(1).max(64).optional().meta(Unrestricted11),
2987
+ surface: z14.string().min(1).max(64).optional().meta(Unrestricted11),
2988
+ plan_handle: z14.string().min(1).max(64).optional().meta(Unrestricted11),
2989
+ entitlement_handle: z14.string().min(1).max(64).optional().meta(Unrestricted11)
2897
2990
  }).meta(
2898
2991
  {
2899
2992
  id: "SdkMetaEvent",
@@ -2985,17 +3078,17 @@ var eventPaths = {
2985
3078
  };
2986
3079
  var { Unrestricted: Unrestricted12 } = DataClassification;
2987
3080
  var { Persisted: Persisted12, Transient: Transient12 } = SchemaPersistence;
2988
- var { Internal: Internal9 } = SchemaExposure;
3081
+ var { Internal: Internal10 } = SchemaExposure;
2989
3082
  var PLAYBOOK_SDK_FACETS6 = schemaFacets(SchemaContext.Playbook, { sdkInput: true });
2990
3083
  var PENDING_PLAYBOOK_SDK_FACETS2 = schemaFacets(SchemaContext.Playbook, {
2991
3084
  inConfig: false,
2992
3085
  sdkInput: true
2993
3086
  });
2994
3087
  var TrialStatusSchema = z15.enum(["not_started", "active", "expired", "converted", "cancelled"]).meta(
2995
- { id: "TrialStatus", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal9 }
3088
+ { id: "TrialStatus", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal10 }
2996
3089
  );
2997
3090
  var TrialLimitTypeSchema = z15.enum(["time", "usage"]).meta(
2998
- { id: "TrialLimitType", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal9 }
3091
+ { id: "TrialLimitType", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal10 }
2999
3092
  );
3000
3093
  var FreeTrialRuleCoreFieldsSchema = z15.object({
3001
3094
  name: NameField.meta(Unrestricted12),
@@ -3043,11 +3136,11 @@ var FreeTrialRuleCoreFieldsSchema = z15.object({
3043
3136
  var FreeTrialRuleSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
3044
3137
  anchor_id: z15.string().min(1).meta({ ...Unrestricted12, readOnly: true })
3045
3138
  }).merge(FreeTrialRuleCoreFieldsSchema).meta(
3046
- { id: "FreeTrialRule", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal9, ...PLAYBOOK_SDK_FACETS6, ...namedIdentity() }
3139
+ { id: "FreeTrialRule", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal10, ...PLAYBOOK_SDK_FACETS6, ...namedIdentity() }
3047
3140
  );
3048
3141
  var FreeTrialRuleAnchorSchema = makeAnchor("FreeTrialRuleAnchor");
3049
3142
  var ReverseTrialStartPolicySchema = z15.enum(["signup", "first_premium_access", "manual"]).meta(
3050
- { id: "ReverseTrialStartPolicy", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal9 }
3143
+ { id: "ReverseTrialStartPolicy", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal10 }
3051
3144
  );
3052
3145
  var ReverseTrialRuleCoreFieldsSchema = z15.object({
3053
3146
  name: NameField.meta(Unrestricted12),
@@ -3068,26 +3161,26 @@ var ReverseTrialRuleCoreFieldsSchema = z15.object({
3068
3161
  var ReverseTrialRuleSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
3069
3162
  anchor_id: z15.string().min(1).meta({ ...Unrestricted12, readOnly: true })
3070
3163
  }).merge(ReverseTrialRuleCoreFieldsSchema).meta(
3071
- { id: "ReverseTrialRule", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal9, ...PLAYBOOK_SDK_FACETS6, ...namedIdentity() }
3164
+ { id: "ReverseTrialRule", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal10, ...PLAYBOOK_SDK_FACETS6, ...namedIdentity() }
3072
3165
  );
3073
3166
  var ReverseTrialRuleAnchorSchema = makeAnchor("ReverseTrialRuleAnchor");
3074
3167
  var TrialLimitPolicySchema = z15.enum(["1_per_lifetime", "1_per_plan", "1_per_year", "unlimited"]).meta(
3075
- { id: "TrialLimitPolicy", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal9 }
3168
+ { id: "TrialLimitPolicy", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal10 }
3076
3169
  );
3077
3170
  var TrialEligibilityScopeSchema = z15.enum(["per_customer", "per_email_domain"]).meta(
3078
- { id: "TrialEligibilityScope", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal9 }
3171
+ { id: "TrialEligibilityScope", "x-revturbine-schema-persistence": Transient12, "x-revturbine-schema-exposure": Internal10 }
3079
3172
  );
3080
3173
  var FreeTrialSettingsSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
3081
3174
  trial_limit_policy: TrialLimitPolicySchema.default("1_per_lifetime").meta(Unrestricted12),
3082
3175
  eligibility_scope: TrialEligibilityScopeSchema.default("per_customer").meta(Unrestricted12)
3083
3176
  }).meta(
3084
- { id: "FreeTrialSettings", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal9, ...PENDING_PLAYBOOK_SDK_FACETS2 }
3177
+ { id: "FreeTrialSettings", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal10, ...PENDING_PLAYBOOK_SDK_FACETS2 }
3085
3178
  );
3086
3179
  var ReverseTrialSettingsSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
3087
3180
  trial_limit_policy: TrialLimitPolicySchema.default("1_per_lifetime").meta(Unrestricted12),
3088
3181
  eligibility_scope: TrialEligibilityScopeSchema.default("per_customer").meta(Unrestricted12)
3089
3182
  }).meta(
3090
- { id: "ReverseTrialSettings", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal9, ...PENDING_PLAYBOOK_SDK_FACETS2 }
3183
+ { id: "ReverseTrialSettings", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal10, ...PENDING_PLAYBOOK_SDK_FACETS2 }
3091
3184
  );
3092
3185
  var TrialInstanceSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
3093
3186
  customer_id: z15.string().min(1).meta(Unrestricted12),
@@ -3127,7 +3220,7 @@ var TrialInstanceSchema = IdField.merge(TimestampFields).merge(TenantIdField).ex
3127
3220
  cancelled_at: NullableDatetimeField.meta(Unrestricted12),
3128
3221
  metadata: MetadataField.meta(Unrestricted12)
3129
3222
  }).meta(
3130
- { id: "TrialInstance", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal9 }
3223
+ { id: "TrialInstance", "x-revturbine-schema-persistence": Persisted12, "x-revturbine-schema-exposure": Internal10 }
3131
3224
  );
3132
3225
  var trialPaths = {
3133
3226
  "/api/free-trial-rule-anchors": {
@@ -3364,16 +3457,16 @@ var trialPaths = {
3364
3457
  };
3365
3458
  var { Unrestricted: Unrestricted13 } = DataClassification;
3366
3459
  var { Persisted: Persisted13, Transient: Transient13 } = SchemaPersistence;
3367
- var { Internal: Internal10 } = SchemaExposure;
3460
+ var { Internal: Internal11 } = SchemaExposure;
3368
3461
  var PENDING_PLAYBOOK_SDK_FACETS3 = schemaFacets(SchemaContext.Playbook, {
3369
3462
  inConfig: false,
3370
3463
  sdkInput: true
3371
3464
  });
3372
3465
  var ExperimentStatusSchema = z16.enum(["draft", "ramping", "winning", "neutral", "needs_attention", "paused", "complete"]).meta(
3373
- { id: "ExperimentStatus", "x-revturbine-schema-persistence": Transient13, "x-revturbine-schema-exposure": Internal10 }
3466
+ { id: "ExperimentStatus", "x-revturbine-schema-persistence": Transient13, "x-revturbine-schema-exposure": Internal11 }
3374
3467
  );
3375
3468
  var ExperimentTypeSchema = z16.enum(["placement_ab", "entitlement_ab", "plan_ab", "pricing_ab", "custom"]).meta(
3376
- { id: "ExperimentType", "x-revturbine-schema-persistence": Transient13, "x-revturbine-schema-exposure": Internal10 }
3469
+ { id: "ExperimentType", "x-revturbine-schema-persistence": Transient13, "x-revturbine-schema-exposure": Internal11 }
3377
3470
  );
3378
3471
  var ExperimentVariantSchema = z16.object({
3379
3472
  variant_id: z16.string().min(1),
@@ -3382,7 +3475,7 @@ var ExperimentVariantSchema = z16.object({
3382
3475
  is_control: z16.boolean().default(false),
3383
3476
  config: z16.record(z16.string(), z16.unknown()).default({})
3384
3477
  }).meta(
3385
- { id: "ExperimentVariant", "x-revturbine-schema-persistence": Persisted13, "x-revturbine-schema-exposure": Internal10, ...PENDING_PLAYBOOK_SDK_FACETS3 }
3478
+ { id: "ExperimentVariant", "x-revturbine-schema-persistence": Persisted13, "x-revturbine-schema-exposure": Internal11, ...PENDING_PLAYBOOK_SDK_FACETS3 }
3386
3479
  );
3387
3480
  var ExperimentSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
3388
3481
  anchor_id: z16.string().min(1).meta({ ...Unrestricted13, readOnly: true }),
@@ -3406,7 +3499,7 @@ var ExperimentSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge
3406
3499
  winning_variant_id: z16.string().nullable().default(null).meta(Unrestricted13),
3407
3500
  metadata: MetadataField.meta(Unrestricted13)
3408
3501
  }).meta(
3409
- { id: "Experiment", "x-revturbine-schema-persistence": Persisted13, "x-revturbine-schema-exposure": Internal10, ...PENDING_PLAYBOOK_SDK_FACETS3, ...namedIdentity() }
3502
+ { id: "Experiment", "x-revturbine-schema-persistence": Persisted13, "x-revturbine-schema-exposure": Internal11, ...PENDING_PLAYBOOK_SDK_FACETS3, ...namedIdentity() }
3410
3503
  );
3411
3504
  var ExperimentAnchorSchema = makeAnchor("ExperimentAnchor");
3412
3505
  var SuggestionSeveritySchema = SeveritySchema;
@@ -3422,7 +3515,7 @@ var OptimizationSuggestionSchema = IdField.merge(TimestampFields).merge(TenantId
3422
3515
  is_dismissed: z16.boolean().default(false).meta(Unrestricted13),
3423
3516
  metadata: MetadataField.meta(Unrestricted13)
3424
3517
  }).meta(
3425
- { id: "OptimizationSuggestion", "x-revturbine-schema-persistence": Persisted13, "x-revturbine-schema-exposure": Internal10 }
3518
+ { id: "OptimizationSuggestion", "x-revturbine-schema-persistence": Persisted13, "x-revturbine-schema-exposure": Internal11 }
3426
3519
  );
3427
3520
  var experimentPaths = {
3428
3521
  "/api/experiment-anchors": {
@@ -3535,15 +3628,15 @@ var experimentPaths = {
3535
3628
  })
3536
3629
  }
3537
3630
  };
3538
- var { Unrestricted: Unrestricted14, Financial: Financial3 } = DataClassification;
3631
+ var { Unrestricted: Unrestricted14, Financial: Financial4 } = DataClassification;
3539
3632
  var { Persisted: Persisted14, Transient: Transient14 } = SchemaPersistence;
3540
- var { Internal: Internal11 } = SchemaExposure;
3633
+ var { Internal: Internal12 } = SchemaExposure;
3541
3634
  var PLAYBOOK_SDK_FACETS7 = schemaFacets(SchemaContext.Playbook, { sdkInput: true });
3542
3635
  var PromotionStatusSchema = z17.enum(["draft", "scheduled", "live", "expired", "archived"]).meta(
3543
- { id: "PromotionStatus", "x-revturbine-schema-persistence": Transient14, "x-revturbine-schema-exposure": Internal11 }
3636
+ { id: "PromotionStatus", "x-revturbine-schema-persistence": Transient14, "x-revturbine-schema-exposure": Internal12 }
3544
3637
  );
3545
3638
  var DiscountTypeSchema = z17.enum(["percentage", "fixed_amount", "free_months"]).meta(
3546
- { id: "DiscountType", "x-revturbine-schema-persistence": Transient14, "x-revturbine-schema-exposure": Internal11 }
3639
+ { id: "DiscountType", "x-revturbine-schema-persistence": Transient14, "x-revturbine-schema-exposure": Internal12 }
3547
3640
  );
3548
3641
  var PromotionSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
3549
3642
  anchor_id: z17.string().min(1).meta({ ...Unrestricted14, readOnly: true }),
@@ -3552,8 +3645,8 @@ var PromotionSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(
3552
3645
  description: z17.string().max(1e3).optional().meta(Unrestricted14),
3553
3646
  rt_status: PromotionStatusSchema.default("draft").meta(Unrestricted14),
3554
3647
  discount_type: DiscountTypeSchema.meta(Unrestricted14),
3555
- discount_value: z17.number().min(0).meta(Financial3),
3556
- currency: z17.string().length(3).default("USD").meta(Financial3),
3648
+ discount_value: z17.number().min(0).meta(Financial4),
3649
+ currency: z17.string().length(3).default("USD").meta(Financial4),
3557
3650
  applicable_plan_ids: z17.array(z17.string()).default([]).meta(Unrestricted14),
3558
3651
  applicable_addon_ids: z17.array(z17.string()).default([]).meta(Unrestricted14),
3559
3652
  target_segment_ids: z17.array(z17.string()).default([]).meta(Unrestricted14),
@@ -3568,7 +3661,7 @@ var PromotionSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(
3568
3661
  auto_sync_stripe: z17.boolean().default(false).meta(Unrestricted14),
3569
3662
  metadata: MetadataField.meta(Unrestricted14)
3570
3663
  }).meta(
3571
- { id: "Promotion", "x-revturbine-schema-persistence": Persisted14, "x-revturbine-schema-exposure": Internal11, ...PLAYBOOK_SDK_FACETS7, ...namedIdentity() }
3664
+ { id: "Promotion", "x-revturbine-schema-persistence": Persisted14, "x-revturbine-schema-exposure": Internal12, ...PLAYBOOK_SDK_FACETS7, ...namedIdentity() }
3572
3665
  );
3573
3666
  var PromotionAnchorSchema = makeAnchor("PromotionAnchor");
3574
3667
  var promotionPaths = {
@@ -3653,7 +3746,7 @@ var promotionPaths = {
3653
3746
  };
3654
3747
  var { Unrestricted: Unrestricted15, Pii: Pii5 } = DataClassification;
3655
3748
  var { Persisted: Persisted15, Transient: Transient15 } = SchemaPersistence;
3656
- var { Internal: Internal12, External: External10 } = SchemaExposure;
3749
+ var { Internal: Internal13, External: External10 } = SchemaExposure;
3657
3750
  var PresentationRecordSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
3658
3751
  customer_id: z18.string().min(1).meta(Pii5),
3659
3752
  placement_id: z18.string().min(1).meta(Unrestricted15),
@@ -3668,7 +3761,7 @@ var PresentationRecordSchema = IdField.merge(TimestampFields).merge(TenantIdFiel
3668
3761
  session_id: z18.string().optional().meta(Unrestricted15),
3669
3762
  metadata: MetadataField.meta(Unrestricted15)
3670
3763
  }).meta(
3671
- { id: "PresentationRecord", "x-revturbine-schema-persistence": Persisted15, "x-revturbine-schema-exposure": Internal12 }
3764
+ { id: "PresentationRecord", "x-revturbine-schema-persistence": Persisted15, "x-revturbine-schema-exposure": Internal13 }
3672
3765
  );
3673
3766
  var DecisionLogSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
3674
3767
  customer_id: z18.string().min(1).meta(Pii5),
@@ -3684,7 +3777,7 @@ var DecisionLogSchema = IdField.merge(TimestampFields).merge(TenantIdField).exte
3684
3777
  variant_id: z18.string().nullable().default(null).meta(Unrestricted15),
3685
3778
  latency_ms: z18.number().min(0).optional().meta(Unrestricted15)
3686
3779
  }).meta(
3687
- { id: "DecisionLog", "x-revturbine-schema-persistence": Persisted15, "x-revturbine-schema-exposure": Internal12 }
3780
+ { id: "DecisionLog", "x-revturbine-schema-persistence": Persisted15, "x-revturbine-schema-exposure": Internal13 }
3688
3781
  );
3689
3782
  var EntitlementEvalLogSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
3690
3783
  customer_id: z18.string().min(1).meta(Pii5),
@@ -3697,7 +3790,7 @@ var EntitlementEvalLogSchema = IdField.merge(TimestampFields).merge(TenantIdFiel
3697
3790
  source_id: z18.string().min(1).meta(Unrestricted15),
3698
3791
  latency_ms: z18.number().min(0).optional().meta(Unrestricted15)
3699
3792
  }).meta(
3700
- { id: "EntitlementEvalLog", "x-revturbine-schema-persistence": Persisted15, "x-revturbine-schema-exposure": Internal12 }
3793
+ { id: "EntitlementEvalLog", "x-revturbine-schema-persistence": Persisted15, "x-revturbine-schema-exposure": Internal13 }
3701
3794
  );
3702
3795
  var runtimePaths = {
3703
3796
  "/api/presentation-records": {
@@ -3733,7 +3826,7 @@ var runtimePaths = {
3733
3826
  };
3734
3827
  var { Unrestricted: Unrestricted16 } = DataClassification;
3735
3828
  var { Persisted: Persisted16, Transient: Transient16 } = SchemaPersistence;
3736
- var { Internal: Internal13, External: External11 } = SchemaExposure;
3829
+ var { Internal: Internal14, External: External11 } = SchemaExposure;
3737
3830
  var PLAYBOOK_SDK_FACETS8 = schemaFacets(SchemaContext.Playbook, { sdkInput: true });
3738
3831
  var PLAYBOOK_AUTHORING_FACETS2 = schemaFacets(SchemaContext.Playbook, { sdkInput: false });
3739
3832
  var PENDING_PLAYBOOK_FACETS4 = schemaFacets(SchemaContext.Playbook, {
@@ -3776,7 +3869,7 @@ var SeatTypeSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(A
3776
3869
  entitlement_ids: z19.array(z19.string()).default([]).meta(Unrestricted16),
3777
3870
  metadata: MetadataField.meta(Unrestricted16)
3778
3871
  }).meta(
3779
- { id: "SeatType", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal13, ...PENDING_PLAYBOOK_FACETS4, ...namedIdentity() }
3872
+ { id: "SeatType", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal14, ...PENDING_PLAYBOOK_FACETS4, ...namedIdentity() }
3780
3873
  );
3781
3874
  var SeatTypeAnchorSchema = makeAnchor("SeatTypeAnchor");
3782
3875
  var PersonalizationTokenSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
@@ -3791,10 +3884,10 @@ var PersonalizationTokenSchema = IdField.merge(TimestampFields).merge(TenantIdFi
3791
3884
  format: z19.enum(["string", "number", "currency", "percentage", "date"]).nullable().default(null).meta(Unrestricted16),
3792
3885
  metadata: MetadataField.meta(Unrestricted16)
3793
3886
  }).meta(
3794
- { id: "PersonalizationToken", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal13, ...PENDING_PLAYBOOK_FACETS4, ...namedIdentity() }
3887
+ { id: "PersonalizationToken", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal14, ...PENDING_PLAYBOOK_FACETS4, ...namedIdentity() }
3795
3888
  );
3796
3889
  var PersonalizationTokenAnchorSchema = makeAnchor("PersonalizationTokenAnchor");
3797
- var OnboardingStateSchema = z19.enum(["not_started", "started", "details_submitted", "charges_enabled", "activated", "deauthorized"]).meta({ id: "OnboardingState", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal13 });
3890
+ var OnboardingStateSchema = z19.enum(["not_started", "started", "details_submitted", "charges_enabled", "activated", "deauthorized"]).meta({ id: "OnboardingState", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal14 });
3798
3891
  var StripeIntegrationConfigSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
3799
3892
  handle: HandleField.meta({ ...Unrestricted16, readOnly: true }),
3800
3893
  stripe_account_id: z19.string().min(1).meta(Unrestricted16),
@@ -3820,7 +3913,7 @@ var StripeIntegrationConfigSchema = IdField.merge(TimestampFields).merge(TenantI
3820
3913
  last_sync_at: z19.string().optional().meta({ ...Unrestricted16, readOnly: true }),
3821
3914
  metadata: MetadataField.meta(Unrestricted16)
3822
3915
  }).meta(
3823
- { id: "StripeIntegrationConfig", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal13, ...BILLING_FACETS2, ...mintedIdentity() }
3916
+ { id: "StripeIntegrationConfig", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal14, ...BILLING_FACETS2, ...mintedIdentity() }
3824
3917
  );
3825
3918
  var BrandingConfigSchema = z19.object({
3826
3919
  theme: z19.record(z19.string(), z19.unknown()).optional().meta(Unrestricted16),
@@ -3845,10 +3938,10 @@ var MeteringConfigSchema = IdField.merge(TimestampFields).merge(TenantIdField).m
3845
3938
  is_active: z19.boolean().default(true).meta(Unrestricted16),
3846
3939
  metadata: MetadataField.meta(Unrestricted16)
3847
3940
  }).meta(
3848
- { id: "MeteringConfig", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal13, ...METERING_FACETS, ...mintedIdentity() }
3941
+ { id: "MeteringConfig", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal14, ...METERING_FACETS, ...mintedIdentity() }
3849
3942
  );
3850
3943
  var EnforcementActionSchema = z19.enum(["block", "warn", "downgrade", "throttle", "notify_admin", "custom"]).meta(
3851
- { id: "EnforcementAction", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal13 }
3944
+ { id: "EnforcementAction", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal14 }
3852
3945
  );
3853
3946
  var UsageEnforcementSettingsSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
3854
3947
  anchor_id: z19.string().min(1).meta({ ...Unrestricted16, readOnly: true }),
@@ -3862,7 +3955,7 @@ var UsageEnforcementSettingsSchema = IdField.merge(TimestampFields).merge(Tenant
3862
3955
  notification_channels: z19.array(z19.enum(["email", "in_app", "webhook"])).default(["in_app"]).meta(Unrestricted16),
3863
3956
  is_active: z19.boolean().default(true).meta(Unrestricted16)
3864
3957
  }).meta(
3865
- { id: "UsageEnforcementSettings", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal13, ...PENDING_PLAYBOOK_SDK_FACETS4, ...mintedIdentity() }
3958
+ { id: "UsageEnforcementSettings", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal14, ...PENDING_PLAYBOOK_SDK_FACETS4, ...mintedIdentity() }
3866
3959
  );
3867
3960
  var UsageEnforcementSettingsAnchorSchema = makeAnchor("UsageEnforcementSettingsAnchor");
3868
3961
  var PlacementSettingsCapRuleGroupItemSchema = z19.object({
@@ -3870,7 +3963,7 @@ var PlacementSettingsCapRuleGroupItemSchema = z19.object({
3870
3963
  id: z19.string().min(1).meta(Unrestricted16),
3871
3964
  label: z19.string().min(1).optional().meta(Unrestricted16)
3872
3965
  }).meta(
3873
- { id: "PlacementSettingsCapRuleGroupItem", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal13 }
3966
+ { id: "PlacementSettingsCapRuleGroupItem", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal14 }
3874
3967
  );
3875
3968
  var PlacementSettingsCapRuleSchema = z19.object({
3876
3969
  id: z19.string().min(1).meta(Unrestricted16),
@@ -3880,17 +3973,21 @@ var PlacementSettingsCapRuleSchema = z19.object({
3880
3973
  period: z19.enum(["session", "day", "week", "month"]).meta(Unrestricted16)
3881
3974
  }).meta(Unrestricted16)
3882
3975
  }).meta(
3883
- { id: "PlacementSettingsCapRule", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal13 }
3976
+ { id: "PlacementSettingsCapRule", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal14 }
3884
3977
  );
3885
3978
  var PlacementTestModeSchema = z19.enum(["off", "test_users", "all_traffic"]).meta(
3886
- { id: "PlacementTestMode", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal13 }
3979
+ { id: "PlacementTestMode", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal14 }
3887
3980
  );
3888
3981
  var PlacementSettingsCapStateSchema = z19.object({
3889
3982
  capRules: z19.array(PlacementSettingsCapRuleSchema).default([]).meta(Unrestricted16),
3890
3983
  sessionCooldownMinutes: z19.number().int().min(0).default(30).meta(Unrestricted16),
3984
+ // Tenant-level default remind-me-later (defer) window, in minutes. A
3985
+ // per-payload `remind_later_minutes` overrides it when set (plan 167 REQ-6,
3986
+ // Q-3). Rides in this global_frequency_cap jsonb wrapper — no column/`.fbs`.
3987
+ remindLaterMinutes: z19.number().int().min(0).default(60).meta(Unrestricted16),
3891
3988
  testMode: PlacementTestModeSchema.default("off").meta(Unrestricted16)
3892
3989
  }).meta(
3893
- { id: "PlacementSettingsCapState", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal13 }
3990
+ { id: "PlacementSettingsCapState", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": Internal14 }
3894
3991
  );
3895
3992
  var PlacementSettingsSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
3896
3993
  anchor_id: z19.string().min(1).meta({ ...Unrestricted16, readOnly: true }),
@@ -3902,11 +3999,12 @@ var PlacementSettingsSchema = IdField.merge(TimestampFields).merge(TenantIdField
3902
3999
  global_frequency_cap_period: z19.enum(["hour", "day", "week", "month", "session"]).nullable().default(null).meta(Unrestricted16),
3903
4000
  suppress_for_paid: z19.boolean().default(false).meta(Unrestricted16),
3904
4001
  suppress_for_trial: z19.boolean().default(false).meta(Unrestricted16),
3905
- default_dismiss_cooldown_hours: z19.number().int().min(0).default(24).meta(Unrestricted16),
4002
+ // `default_dismiss_cooldown_hours` removed (plan 167 Q-2): the dismiss
4003
+ // cooldown is defined per-payload in days (`cooldown_after_dismiss_days`).
3906
4004
  allow_stacking: z19.boolean().default(false).meta(Unrestricted16),
3907
4005
  priority_collision_strategy: z19.enum(["highest_priority", "most_recent", "random"]).default("highest_priority").meta(Unrestricted16)
3908
4006
  }).meta(
3909
- { id: "PlacementSettings", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal13, ...PENDING_PLAYBOOK_SDK_FACETS4, ...mintedIdentity() }
4007
+ { id: "PlacementSettings", "x-revturbine-schema-persistence": Persisted16, "x-revturbine-schema-exposure": Internal14, ...PENDING_PLAYBOOK_SDK_FACETS4, ...mintedIdentity() }
3910
4008
  );
3911
4009
  var PlacementSettingsAnchorSchema = makeAnchor("PlacementSettingsAnchor");
3912
4010
  var RevTurbineConfigSegmentsItemPredicatesItemSchema = z19.object({
@@ -4014,7 +4112,7 @@ var RevTurbineConfigPlacementSettingsItemSchema = z19.object({
4014
4112
  global_frequency_cap_period: z19.enum(["hour", "day", "week", "month", "session"]).nullable().default(null).meta(Unrestricted16),
4015
4113
  suppress_for_paid: z19.boolean().default(false).meta(Unrestricted16),
4016
4114
  suppress_for_trial: z19.boolean().default(false).meta(Unrestricted16),
4017
- default_dismiss_cooldown_hours: z19.number().int().min(0).nullable().default(null).meta(Unrestricted16),
4115
+ // `default_dismiss_cooldown_hours` removed (plan 167 Q-2).
4018
4116
  allow_stacking: z19.boolean().default(false).meta(Unrestricted16),
4019
4117
  priority_collision_strategy: z19.string().nullable().default(null).meta(Unrestricted16)
4020
4118
  }).meta(
@@ -4156,7 +4254,11 @@ var RevTurbineConfigUiPathActionTypeSchema = z19.enum([
4156
4254
  "verify_work_email",
4157
4255
  "update_payment_method",
4158
4256
  "enable_auto_renewal",
4159
- "manage_subscription"
4257
+ "manage_subscription",
4258
+ // Authored `snooze` resolves through to the SDK's remind-later path
4259
+ // (plan 167 windows); previously it fell through as an invalid type
4260
+ // (plan 174 TASK-6 / Q-5, spec-check F-65a).
4261
+ "snooze"
4160
4262
  ]).meta(
4161
4263
  { id: "RevTurbineConfigUiPathActionType", "x-revturbine-schema-persistence": Transient16, "x-revturbine-schema-exposure": External11 }
4162
4264
  );
@@ -4265,6 +4367,8 @@ var RevTurbineConfigStudioPayloadSchema = z19.object({
4265
4367
  caps: RevTurbineConfigStudioPayloadCapsSchema.optional().meta(Unrestricted16),
4266
4368
  // Optional slot targeting (spec §3.1.1): empty/absent = any compatible slot.
4267
4369
  surface_slot_ids: z19.array(z19.string()).optional().meta(Unrestricted16),
4370
+ // Per-payload remind-me-later override (minutes); absent = inherit tenant default (plan 167 Q-3).
4371
+ remind_later_minutes: z19.number().int().min(0).nullable().optional().meta(Unrestricted16),
4268
4372
  created_at: z19.string().optional().meta({ ...Unrestricted16, readOnly: true }),
4269
4373
  recommendation_strategy: z19.enum(["next_tier_up", "best_value", "custom"]).optional().default("next_tier_up").meta(Unrestricted16),
4270
4374
  recommendation_plan_override: z19.string().optional().meta(Unrestricted16)
@@ -4304,6 +4408,8 @@ var RevTurbineConfigPlacementPayloadItemSchema = z19.object({
4304
4408
  placement_id: z19.string().min(1).meta(Unrestricted16),
4305
4409
  target: RevTurbineConfigStudioPayloadTargetSchema.meta(Unrestricted16),
4306
4410
  caps: RevTurbineConfigStudioPayloadCapsSchema.optional().meta(Unrestricted16),
4411
+ // Per-payload remind-me-later override (minutes); absent = inherit tenant default (plan 167 Q-3).
4412
+ remind_later_minutes: z19.number().int().min(0).nullable().optional().meta(Unrestricted16),
4307
4413
  created_at: z19.string().meta({ ...Unrestricted16, readOnly: true }),
4308
4414
  updated_at: z19.string().datetime().optional().meta({ ...Unrestricted16, readOnly: true }),
4309
4415
  source_mode: z19.enum(["inline", "content_linked"]).meta(Unrestricted16),
@@ -4534,6 +4640,12 @@ var PlaybookSchema = z19.preprocess(normalizeConfigHeaderInput, PlaybookObjectSc
4534
4640
  "x-revturbine-schema-exposure": External11,
4535
4641
  ...PLAYBOOK_SDK_FACETS8
4536
4642
  });
4643
+ var PlaybookStrictSchema = z19.preprocess(normalizeConfigHeaderInput, PlaybookObjectSchema.strict()).meta({
4644
+ id: "PlaybookStrict",
4645
+ "x-revturbine-schema-persistence": Transient16,
4646
+ "x-revturbine-schema-exposure": External11,
4647
+ ...PLAYBOOK_SDK_FACETS8
4648
+ });
4537
4649
  var RevTurbineConfigSchema = PlaybookSchema;
4538
4650
  var configPaths = {
4539
4651
  "/api/seat-type-anchors": {
@@ -4773,9 +4885,9 @@ var configPaths = {
4773
4885
  };
4774
4886
  var { Unrestricted: Unrestricted17 } = DataClassification;
4775
4887
  var { Persisted: Persisted17 } = SchemaPersistence;
4776
- var { Internal: Internal14 } = SchemaExposure;
4888
+ var { Internal: Internal15 } = SchemaExposure;
4777
4889
  var ChangeLogActionSchema = z20.enum(["create", "update", "delete", "archive", "restore", "reorder", "duplicate", "sync", "publish"]).meta(
4778
- { id: "ChangeLogAction", "x-revturbine-schema-persistence": Persisted17, "x-revturbine-schema-exposure": Internal14 }
4890
+ { id: "ChangeLogAction", "x-revturbine-schema-persistence": Persisted17, "x-revturbine-schema-exposure": Internal15 }
4779
4891
  );
4780
4892
  var ChangeLogEntrySchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
4781
4893
  action: ChangeLogActionSchema.meta(Unrestricted17),
@@ -4791,7 +4903,7 @@ var ChangeLogEntrySchema = IdField.merge(TimestampFields).merge(TenantIdField).e
4791
4903
  summary: z20.string().max(1e3).optional().meta(Unrestricted17),
4792
4904
  metadata: MetadataField.meta(Unrestricted17)
4793
4905
  }).meta(
4794
- { id: "ChangeLogEntry", "x-revturbine-schema-persistence": Persisted17, "x-revturbine-schema-exposure": Internal14 }
4906
+ { id: "ChangeLogEntry", "x-revturbine-schema-persistence": Persisted17, "x-revturbine-schema-exposure": Internal15 }
4795
4907
  );
4796
4908
  var changelogPaths = {
4797
4909
  "/api/changelog": {
@@ -4817,9 +4929,9 @@ var changelogPaths = {
4817
4929
  };
4818
4930
  var { Unrestricted: Unrestricted18 } = DataClassification;
4819
4931
  var { Persisted: Persisted18, Transient: Transient17 } = SchemaPersistence;
4820
- var { Internal: Internal15 } = SchemaExposure;
4932
+ var { Internal: Internal16 } = SchemaExposure;
4821
4933
  var TenantStatusSchema = z21.enum(["active", "suspended", "archived"]).meta(
4822
- { id: "TenantStatus", "x-revturbine-schema-persistence": Transient17, "x-revturbine-schema-exposure": Internal15 }
4934
+ { id: "TenantStatus", "x-revturbine-schema-persistence": Transient17, "x-revturbine-schema-exposure": Internal16 }
4823
4935
  );
4824
4936
  var TenantSchema = IdField.merge(TimestampFields).extend({
4825
4937
  name: NameField.meta(Unrestricted18),
@@ -4827,7 +4939,7 @@ var TenantSchema = IdField.merge(TimestampFields).extend({
4827
4939
  status: TenantStatusSchema.default("active").meta(Unrestricted18),
4828
4940
  metadata: MetadataField.meta(Unrestricted18)
4829
4941
  }).meta(
4830
- { id: "Tenant", "x-revturbine-schema-persistence": Persisted18, "x-revturbine-schema-exposure": Internal15 }
4942
+ { id: "Tenant", "x-revturbine-schema-persistence": Persisted18, "x-revturbine-schema-exposure": Internal16 }
4831
4943
  );
4832
4944
  var tenantPaths = {
4833
4945
  "/api/tenants": {
@@ -4893,9 +5005,9 @@ var tenantPaths = {
4893
5005
  };
4894
5006
  var { Unrestricted: Unrestricted19 } = DataClassification;
4895
5007
  var { Persisted: Persisted19, Transient: Transient18 } = SchemaPersistence;
4896
- var { Internal: Internal16 } = SchemaExposure;
5008
+ var { Internal: Internal17 } = SchemaExposure;
4897
5009
  var EnvironmentStatusSchema = z22.enum(["active", "archived", "locked"]).meta(
4898
- { id: "EnvironmentStatus", "x-revturbine-schema-persistence": Transient18, "x-revturbine-schema-exposure": Internal16 }
5010
+ { id: "EnvironmentStatus", "x-revturbine-schema-persistence": Transient18, "x-revturbine-schema-exposure": Internal17 }
4899
5011
  );
4900
5012
  var EnvironmentSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
4901
5013
  name: NameField.meta(Unrestricted19),
@@ -4914,7 +5026,7 @@ var EnvironmentSchema = IdField.merge(TimestampFields).merge(TenantIdField).exte
4914
5026
  created_by: z22.string().optional().meta(Unrestricted19),
4915
5027
  metadata: MetadataField.meta(Unrestricted19)
4916
5028
  }).meta(
4917
- { id: "Environment", "x-revturbine-schema-persistence": Persisted19, "x-revturbine-schema-exposure": Internal16 }
5029
+ { id: "Environment", "x-revturbine-schema-persistence": Persisted19, "x-revturbine-schema-exposure": Internal17 }
4918
5030
  );
4919
5031
  var EnvironmentPromotionRequestSchema = z22.object({
4920
5032
  source_environment_id: z22.string().min(1),
@@ -4922,7 +5034,7 @@ var EnvironmentPromotionRequestSchema = z22.object({
4922
5034
  playbook_version_ids: z22.array(z22.string()).optional(),
4923
5035
  strategy: z22.enum(["all_current", "selected_playbook_versions"]).default("all_current")
4924
5036
  }).meta(
4925
- { id: "EnvironmentPromotionRequest", "x-revturbine-schema-persistence": Transient18, "x-revturbine-schema-exposure": Internal16 }
5037
+ { id: "EnvironmentPromotionRequest", "x-revturbine-schema-persistence": Transient18, "x-revturbine-schema-exposure": Internal17 }
4926
5038
  );
4927
5039
  var environmentPaths = {
4928
5040
  "/api/environments": {
@@ -5101,7 +5213,7 @@ var ServerEvaluationPayloadSchema = z23.object({
5101
5213
  }).meta({ id: "ServerEvaluationPayload", "x-revturbine-schema-persistence": Transient19, "x-revturbine-schema-exposure": External12 });
5102
5214
  var { Unrestricted: Unrestricted21 } = DataClassification;
5103
5215
  var { Persisted: Persisted21, Transient: Transient20 } = SchemaPersistence;
5104
- var { Internal: Internal17 } = SchemaExposure;
5216
+ var { Internal: Internal18 } = SchemaExposure;
5105
5217
  var PlaybookVersionStatusSchema = z24.enum([
5106
5218
  "draft",
5107
5219
  "awaiting_approval",
@@ -5111,7 +5223,7 @@ var PlaybookVersionStatusSchema = z24.enum([
5111
5223
  "rejected",
5112
5224
  "archived"
5113
5225
  ]).meta(
5114
- { id: "PlaybookVersionStatus", "x-revturbine-schema-persistence": Transient20, "x-revturbine-schema-exposure": Internal17 }
5226
+ { id: "PlaybookVersionStatus", "x-revturbine-schema-persistence": Transient20, "x-revturbine-schema-exposure": Internal18 }
5115
5227
  );
5116
5228
  var PlaybookVersionSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
5117
5229
  environment_id: z24.string().min(1).meta(Unrestricted21),
@@ -5148,7 +5260,7 @@ var PlaybookVersionSchema = IdField.merge(TimestampFields).merge(TenantIdField).
5148
5260
  bundle: z24.string().nullable().default(null).meta({ ...Unrestricted21, readOnly: true }),
5149
5261
  metadata: MetadataField.meta(Unrestricted21)
5150
5262
  }).meta(
5151
- { id: "PlaybookVersion", "x-revturbine-schema-persistence": Persisted21, "x-revturbine-schema-exposure": Internal17 }
5263
+ { id: "PlaybookVersion", "x-revturbine-schema-persistence": Persisted21, "x-revturbine-schema-exposure": Internal18 }
5152
5264
  );
5153
5265
  var PlaybookVersionEntrySummarySchema = z24.object({
5154
5266
  handle: z24.string().meta(Unrestricted21),
@@ -5157,7 +5269,7 @@ var PlaybookVersionEntrySummarySchema = z24.object({
5157
5269
  action: z24.enum(["create", "update", "delete"]).meta(Unrestricted21),
5158
5270
  has_conflict: z24.boolean().meta(Unrestricted21)
5159
5271
  }).meta(
5160
- { id: "PlaybookVersionEntrySummary", "x-revturbine-schema-persistence": Transient20, "x-revturbine-schema-exposure": Internal17 }
5272
+ { id: "PlaybookVersionEntrySummary", "x-revturbine-schema-persistence": Transient20, "x-revturbine-schema-exposure": Internal18 }
5161
5273
  );
5162
5274
  var PlaybookVersionDiffSchema = z24.object({
5163
5275
  playbook_version_id: z24.string().meta(Unrestricted21),
@@ -5166,7 +5278,7 @@ var PlaybookVersionDiffSchema = z24.object({
5166
5278
  total_conflicts: z24.number().int().min(0).meta(Unrestricted21),
5167
5279
  deployable: z24.boolean().meta(Unrestricted21)
5168
5280
  }).meta(
5169
- { id: "PlaybookVersionDiff", "x-revturbine-schema-persistence": Transient20, "x-revturbine-schema-exposure": Internal17 }
5281
+ { id: "PlaybookVersionDiff", "x-revturbine-schema-persistence": Transient20, "x-revturbine-schema-exposure": Internal18 }
5170
5282
  );
5171
5283
  var PlaybookVersionDeployResultSchema = z24.object({
5172
5284
  playbook_version_id: z24.string().meta(Unrestricted21),
@@ -5175,7 +5287,7 @@ var PlaybookVersionDeployResultSchema = z24.object({
5175
5287
  skipped_conflicts: z24.number().int().min(0).meta(Unrestricted21),
5176
5288
  deployed_at: z24.string().datetime().meta(Unrestricted21)
5177
5289
  }).meta(
5178
- { id: "PlaybookVersionDeployResult", "x-revturbine-schema-persistence": Transient20, "x-revturbine-schema-exposure": Internal17 }
5290
+ { id: "PlaybookVersionDeployResult", "x-revturbine-schema-persistence": Transient20, "x-revturbine-schema-exposure": Internal18 }
5179
5291
  );
5180
5292
  var playbookVersionPaths = {
5181
5293
  // ── Lifecycle transitions ────────────────────────────────────────────────
@@ -5302,8 +5414,8 @@ var playbookVersionPaths = {
5302
5414
  };
5303
5415
  var { Unrestricted: Unrestricted22, Pii: Pii7 } = DataClassification;
5304
5416
  var { Persisted: Persisted22 } = SchemaPersistence;
5305
- var { Internal: Internal18 } = SchemaExposure;
5306
- var ApiKeyStatusSchema = z25.enum(["active", "revoked", "rotating"]).meta({ id: "ApiKeyStatus", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5417
+ var { Internal: Internal19 } = SchemaExposure;
5418
+ var ApiKeyStatusSchema = z25.enum(["active", "revoked", "rotating"]).meta({ id: "ApiKeyStatus", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5307
5419
  var ApiKeySchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
5308
5420
  name: NameField.meta(Unrestricted22),
5309
5421
  key_hash: z25.string().min(1).meta({ ...Pii7, readOnly: true }),
@@ -5312,22 +5424,22 @@ var ApiKeySchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
5312
5424
  status: ApiKeyStatusSchema.default("active").meta(Unrestricted22),
5313
5425
  last_used_at: NullableDatetimeField.meta({ ...Unrestricted22, readOnly: true }),
5314
5426
  expires_at: NullableDatetimeField.meta(Unrestricted22)
5315
- }).meta({ id: "ApiKey", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5316
- var FlagValueTypeSchema = z25.enum(["boolean", "string", "number", "json"]).meta({ id: "FlagValueType", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5427
+ }).meta({ id: "ApiKey", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5428
+ var FlagValueTypeSchema = z25.enum(["boolean", "string", "number", "json"]).meta({ id: "FlagValueType", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5317
5429
  var FeatureFlagSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
5318
5430
  key: z25.string().min(1).max(100).meta(Unrestricted22),
5319
5431
  value_type: FlagValueTypeSchema.default("boolean").meta(Unrestricted22),
5320
5432
  value: z25.string().max(4e3).default("false").meta(Unrestricted22),
5321
5433
  description: DescriptionField.meta(Unrestricted22),
5322
5434
  enabled: z25.boolean().default(true).meta(Unrestricted22)
5323
- }).meta({ id: "FeatureFlag", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5435
+ }).meta({ id: "FeatureFlag", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5324
5436
  var TenantConfigSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
5325
5437
  workspace_name: z25.string().min(1).max(200).meta(Unrestricted22),
5326
5438
  support_email: z25.string().email().nullable().default(null).meta(Unrestricted22),
5327
5439
  timezone: z25.string().max(50).default("UTC").meta(Unrestricted22),
5328
5440
  default_currency: z25.string().length(3).default("USD").meta(Unrestricted22),
5329
5441
  logo_url: z25.string().url().nullable().default(null).meta(Unrestricted22)
5330
- }).meta({ id: "TenantConfig", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5442
+ }).meta({ id: "TenantConfig", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5331
5443
  var McpConfigSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
5332
5444
  /** @deprecated Plan 28 ships a hosted MCP server at `/api/mcp/streamable-http`; no outbound server URL is needed. Column remains for backward compatibility. */
5333
5445
  server_url: z25.string().url().max(500).meta(Unrestricted22),
@@ -5336,14 +5448,14 @@ var McpConfigSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend
5336
5448
  allow_write_actions: z25.boolean().default(false).meta(Unrestricted22),
5337
5449
  enabled_tools: z25.array(z25.string().max(100)).default([]).meta(Unrestricted22),
5338
5450
  enabled: z25.boolean().default(false).meta(Unrestricted22)
5339
- }).meta({ id: "McpConfig", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5451
+ }).meta({ id: "McpConfig", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5340
5452
  var OnboardingChecklistSchema = IdField.merge(TimestampFields).merge(TenantIdField).extend({
5341
5453
  step_key: z25.string().min(1).max(100).meta(Unrestricted22),
5342
5454
  label: z25.string().min(1).max(200).meta(Unrestricted22),
5343
5455
  done: z25.boolean().default(false).meta(Unrestricted22),
5344
5456
  completed_at: NullableDatetimeField.meta({ ...Unrestricted22, readOnly: true })
5345
- }).meta({ id: "OnboardingChecklist", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5346
- var AuditActorTypeSchema = z25.enum(["user", "agent", "system", "webhook"]).meta({ id: "AuditActorType", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5457
+ }).meta({ id: "OnboardingChecklist", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5458
+ var AuditActorTypeSchema = z25.enum(["user", "agent", "system", "webhook"]).meta({ id: "AuditActorType", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5347
5459
  var AuditEventSchema = IdField.merge(TenantIdField).extend({
5348
5460
  environment_id: z25.string().min(1).default("production").meta(Unrestricted22),
5349
5461
  actor_type: AuditActorTypeSchema.meta(Unrestricted22),
@@ -5353,15 +5465,15 @@ var AuditEventSchema = IdField.merge(TenantIdField).extend({
5353
5465
  object_id: z25.string().max(200).nullable().default(null).meta(Unrestricted22),
5354
5466
  payload: z25.record(z25.string(), z25.unknown()).nullable().default(null).meta(Unrestricted22),
5355
5467
  occurred_at: z25.string().datetime().meta({ ...Unrestricted22, readOnly: true })
5356
- }).meta({ id: "AuditEvent", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5357
- var PlacementTestUserIdentifierTypeSchema = z25.enum(["user_id", "account_id", "email"]).meta({ id: "PlacementTestUserIdentifierType", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18 });
5468
+ }).meta({ id: "AuditEvent", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5469
+ var PlacementTestUserIdentifierTypeSchema = z25.enum(["user_id", "account_id", "email"]).meta({ id: "PlacementTestUserIdentifierType", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19 });
5358
5470
  var PlacementTestUserSchema = IdField.merge(TimestampFields).merge(TenantIdField).merge(AnchorFields).merge(VersionFields).extend({
5359
5471
  handle: HandleField.meta({ ...Unrestricted22, readOnly: true }),
5360
5472
  identifier: z25.string().min(1).max(200).meta(Unrestricted22),
5361
5473
  identifier_type: PlacementTestUserIdentifierTypeSchema.default("user_id").meta(Unrestricted22),
5362
5474
  note: z25.string().max(500).nullable().default(null).meta(Unrestricted22),
5363
5475
  added_by: z25.string().meta(Unrestricted22)
5364
- }).meta({ id: "PlacementTestUser", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal18, ...mintedIdentity() });
5476
+ }).meta({ id: "PlacementTestUser", "x-revturbine-schema-persistence": Persisted22, "x-revturbine-schema-exposure": Internal19, ...mintedIdentity() });
5365
5477
  var settingsPaths = {
5366
5478
  // ── API Keys ─────────────────────────────────────────────────────────────
5367
5479
  "/api/settings/api-keys": {
@@ -5547,8 +5659,8 @@ var settingsPaths = {
5547
5659
  };
5548
5660
  var { Unrestricted: Unrestricted23, Pii: Pii8 } = DataClassification;
5549
5661
  var { Persisted: Persisted23, Transient: Transient21 } = SchemaPersistence;
5550
- var { Internal: Internal19 } = SchemaExposure;
5551
- var UserRoleSchema = z26.enum(["user", "admin"]).meta({ id: "UserRole", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5662
+ var { Internal: Internal20 } = SchemaExposure;
5663
+ var UserRoleSchema = z26.enum(["user", "admin"]).meta({ id: "UserRole", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5552
5664
  var AuthUserSchema = IdField.merge(TimestampFields).extend({
5553
5665
  name: NameField.meta(Unrestricted23),
5554
5666
  email: z26.string().email().meta(Pii8),
@@ -5559,7 +5671,7 @@ var AuthUserSchema = IdField.merge(TimestampFields).extend({
5559
5671
  ban_reason: z26.string().nullable().default(null).meta({ ...Unrestricted23, readOnly: true }),
5560
5672
  ban_expires: NullableDatetimeField.meta({ ...Unrestricted23, readOnly: true }),
5561
5673
  two_factor_enabled: z26.boolean().default(false).meta({ ...Unrestricted23, readOnly: true })
5562
- }).meta({ id: "AuthUser", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5674
+ }).meta({ id: "AuthUser", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5563
5675
  var AuthSessionSchema = IdField.merge(TimestampFields).extend({
5564
5676
  expires_at: z26.string().datetime().meta(Unrestricted23),
5565
5677
  token: z26.string().min(1).meta({ ...Pii8, readOnly: true }),
@@ -5568,7 +5680,7 @@ var AuthSessionSchema = IdField.merge(TimestampFields).extend({
5568
5680
  user_id: z26.string().min(1).meta({ ...Unrestricted23, readOnly: true }),
5569
5681
  active_organization_id: z26.string().nullable().default(null).meta(Unrestricted23),
5570
5682
  impersonated_by: z26.string().nullable().default(null).meta({ ...Unrestricted23, readOnly: true })
5571
- }).meta({ id: "AuthSession", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5683
+ }).meta({ id: "AuthSession", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5572
5684
  var AuthAccountSchema = IdField.merge(TimestampFields).extend({
5573
5685
  account_id: z26.string().min(1).meta(Unrestricted23),
5574
5686
  provider_id: z26.string().min(1).meta(Unrestricted23),
@@ -5580,26 +5692,26 @@ var AuthAccountSchema = IdField.merge(TimestampFields).extend({
5580
5692
  refresh_token_expires_at: NullableDatetimeField.meta({ ...Unrestricted23, readOnly: true }),
5581
5693
  scope: z26.string().nullable().default(null).meta(Unrestricted23),
5582
5694
  password: z26.string().nullable().default(null).meta({ ...Pii8, readOnly: true })
5583
- }).meta({ id: "AuthAccount", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5695
+ }).meta({ id: "AuthAccount", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5584
5696
  var AuthVerificationSchema = IdField.merge(TimestampFields).extend({
5585
5697
  identifier: z26.string().min(1).meta(Pii8),
5586
5698
  value: z26.string().min(1).meta({ ...Pii8, readOnly: true }),
5587
5699
  expires_at: z26.string().datetime().meta(Unrestricted23)
5588
- }).meta({ id: "AuthVerification", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5700
+ }).meta({ id: "AuthVerification", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5589
5701
  var AuthTwoFactorSchema = IdField.extend({
5590
5702
  secret: z26.string().min(1).meta({ ...Pii8, readOnly: true }),
5591
5703
  backup_codes: z26.string().min(1).meta({ ...Pii8, readOnly: true }),
5592
5704
  user_id: z26.string().min(1).meta({ ...Unrestricted23, readOnly: true }),
5593
5705
  verified: z26.boolean().default(false).meta({ ...Unrestricted23, readOnly: true })
5594
- }).meta({ id: "AuthTwoFactor", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5706
+ }).meta({ id: "AuthTwoFactor", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5595
5707
  var AuthOrganizationSchema = IdField.extend({
5596
5708
  name: NameField.meta(Unrestricted23),
5597
5709
  slug: z26.string().min(1).max(100).nullable().default(null).meta(Unrestricted23),
5598
5710
  logo: z26.string().url().nullable().default(null).meta(Unrestricted23),
5599
5711
  created_at: z26.string().datetime().meta({ ...Unrestricted23, readOnly: true }),
5600
5712
  metadata: z26.string().nullable().default(null).meta(Unrestricted23)
5601
- }).meta({ id: "AuthOrganization", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5602
- var RoleSchema = z26.enum(["viewer", "collaborator", "approver", "admin"]).meta({ id: "Role", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5713
+ }).meta({ id: "AuthOrganization", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5714
+ var RoleSchema = z26.enum(["viewer", "collaborator", "approver", "admin"]).meta({ id: "Role", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5603
5715
  var PermissionResourceSchema = z26.enum([
5604
5716
  "tenant",
5605
5717
  "users",
@@ -5614,7 +5726,7 @@ var PermissionResourceSchema = z26.enum([
5614
5726
  "mcp",
5615
5727
  "api_tokens",
5616
5728
  "settings"
5617
- ]).meta({ id: "PermissionResource", "x-revturbine-schema-persistence": Transient21, "x-revturbine-schema-exposure": Internal19 });
5729
+ ]).meta({ id: "PermissionResource", "x-revturbine-schema-persistence": Transient21, "x-revturbine-schema-exposure": Internal20 });
5618
5730
  var PermissionActionSchema = z26.enum([
5619
5731
  "read",
5620
5732
  "create",
@@ -5624,11 +5736,11 @@ var PermissionActionSchema = z26.enum([
5624
5736
  "approve",
5625
5737
  "invite",
5626
5738
  "manage_roles"
5627
- ]).meta({ id: "PermissionAction", "x-revturbine-schema-persistence": Transient21, "x-revturbine-schema-exposure": Internal19 });
5739
+ ]).meta({ id: "PermissionAction", "x-revturbine-schema-persistence": Transient21, "x-revturbine-schema-exposure": Internal20 });
5628
5740
  var PermissionSchema = z26.object({
5629
5741
  resource: PermissionResourceSchema,
5630
5742
  action: PermissionActionSchema
5631
- }).meta({ id: "Permission", "x-revturbine-schema-persistence": Transient21, "x-revturbine-schema-exposure": Internal19 });
5743
+ }).meta({ id: "Permission", "x-revturbine-schema-persistence": Transient21, "x-revturbine-schema-exposure": Internal20 });
5632
5744
  var VIEWER_RESOURCES = [
5633
5745
  "tenant",
5634
5746
  "plans",
@@ -5697,14 +5809,14 @@ var ADMIN_PERMS = expand(ADMIN_FULL, ADMIN_ACTIONS);
5697
5809
  var SCOPE_VALUES = PermissionResourceSchema.options.flatMap(
5698
5810
  (resource) => PermissionActionSchema.options.map((action) => `${resource}:${action}`)
5699
5811
  );
5700
- var McpTokenScopeSchema = z26.enum(SCOPE_VALUES).meta({ id: "McpTokenScope", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5812
+ var McpTokenScopeSchema = z26.enum(SCOPE_VALUES).meta({ id: "McpTokenScope", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5701
5813
  var AuthMemberSchema = IdField.extend({
5702
5814
  organization_id: z26.string().min(1).meta({ ...Unrestricted23, readOnly: true }),
5703
5815
  user_id: z26.string().min(1).meta({ ...Unrestricted23, readOnly: true }),
5704
5816
  role: RoleSchema.default("viewer").meta(Unrestricted23),
5705
5817
  created_at: z26.string().datetime().meta({ ...Unrestricted23, readOnly: true })
5706
- }).meta({ id: "AuthMember", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5707
- var InvitationStatusSchema = z26.enum(["pending", "accepted", "rejected", "canceled", "expired"]).meta({ id: "InvitationStatus", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5818
+ }).meta({ id: "AuthMember", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5819
+ var InvitationStatusSchema = z26.enum(["pending", "accepted", "rejected", "canceled", "expired"]).meta({ id: "InvitationStatus", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5708
5820
  var AuthInvitationSchema = IdField.extend({
5709
5821
  organization_id: z26.string().min(1).meta({ ...Unrestricted23, readOnly: true }),
5710
5822
  email: z26.string().email().meta(Pii8),
@@ -5713,7 +5825,7 @@ var AuthInvitationSchema = IdField.extend({
5713
5825
  expires_at: z26.string().datetime().meta(Unrestricted23),
5714
5826
  created_at: z26.string().datetime().meta({ ...Unrestricted23, readOnly: true }),
5715
5827
  inviter_id: z26.string().min(1).meta({ ...Unrestricted23, readOnly: true })
5716
- }).meta({ id: "AuthInvitation", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5828
+ }).meta({ id: "AuthInvitation", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5717
5829
  var AuthPasskeySchema = IdField.extend({
5718
5830
  name: z26.string().max(200).nullable().default(null).meta(Unrestricted23),
5719
5831
  public_key: z26.string().min(1).meta({ ...Pii8, readOnly: true }),
@@ -5725,7 +5837,7 @@ var AuthPasskeySchema = IdField.extend({
5725
5837
  transports: z26.string().nullable().default(null).meta(Unrestricted23),
5726
5838
  created_at: z26.string().datetime().meta({ ...Unrestricted23, readOnly: true }),
5727
5839
  aaguid: z26.string().nullable().default(null).meta(Unrestricted23)
5728
- }).meta({ id: "AuthPasskey", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5840
+ }).meta({ id: "AuthPasskey", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5729
5841
  var AuthApiKeySchema = IdField.merge(TimestampFields).extend({
5730
5842
  config_id: z26.string().min(1).meta(Unrestricted23),
5731
5843
  name: z26.string().max(200).nullable().default(null).meta(Unrestricted23),
@@ -5746,7 +5858,7 @@ var AuthApiKeySchema = IdField.merge(TimestampFields).extend({
5746
5858
  expires_at: NullableDatetimeField.meta(Unrestricted23),
5747
5859
  permissions: z26.string().nullable().default(null).meta(Unrestricted23),
5748
5860
  metadata: z26.string().nullable().default(null).meta(Unrestricted23)
5749
- }).meta({ id: "AuthApiKey", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5861
+ }).meta({ id: "AuthApiKey", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5750
5862
  var AuthSsoProviderSchema = IdField.extend({
5751
5863
  issuer: z26.string().min(1).meta(Unrestricted23),
5752
5864
  oidc_config: z26.string().nullable().default(null).meta(Unrestricted23),
@@ -5755,7 +5867,7 @@ var AuthSsoProviderSchema = IdField.extend({
5755
5867
  provider_id: z26.string().min(1).meta(Unrestricted23),
5756
5868
  organization_id: z26.string().nullable().default(null).meta(Unrestricted23),
5757
5869
  domain: z26.string().min(1).meta(Unrestricted23)
5758
- }).meta({ id: "AuthSsoProvider", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal19 });
5870
+ }).meta({ id: "AuthSsoProvider", "x-revturbine-schema-persistence": Persisted23, "x-revturbine-schema-exposure": Internal20 });
5759
5871
 
5760
5872
  // src/schema/validators.snapshot.mjs
5761
5873
  import { z as z27 } from "zod";
@@ -5827,19 +5939,53 @@ var CATALOG = {
5827
5939
  message: "Plan '{plan}' has no Stripe price linked.",
5828
5940
  specRef: "optimization-studio-ui.md \xA73.1; plans-entitlements-studio-ui.md \xA72.2"
5829
5941
  },
5830
- // entitlement-rule overlap. Origin: the `rule.overlap` check (plan 40).
5942
+ // entitlement-rule overlap. Origin: the `rule.overlap` check (plan 40);
5943
+ // scoped to same-entitlement pairs per §5.8 (plan 179 / devkit #597).
5831
5944
  "VAL-PLN-05": {
5832
5945
  id: "VAL-PLN-05",
5833
5946
  severity: "warning",
5834
- message: "These entitlement rules target the same plan and segment \u2014 only one will apply.",
5947
+ message: "These rules for the same entitlement target the same plan and segment \u2014 only one will apply.",
5835
5948
  specRef: "config-validation.md \xA75.3 (provisional \u2014 plan 73 Q-1)"
5836
5949
  },
5950
+ // limit rule with unset enforcement. Promoted from §5.8 (plan 179 Q-6,
5951
+ // Kent 2026-08-12): unset enforcement silently means "hard-block at the
5952
+ // cap" (evaluator default since plan 34) — an author who wanted degrade or
5953
+ // allow_overage gets a hard stop without being told. Explicitness warn on
5954
+ // the corrected premise (the old "never blocks" mechanism was the SDK
5955
+ // ignoring allowed:false, fixed in sdk 0.2.75).
5956
+ "VAL-PLN-07": {
5957
+ id: "VAL-PLN-07",
5958
+ severity: "warning",
5959
+ message: "This limit rule sets no enforcement \u2014 at the cap it blocks by default. Set enforcement explicitly (hard_block, soft_block, degrade, allow_overage) if that isn't the intent.",
5960
+ specRef: "config-validation.md \xA75.8 (promoted \u2014 plan 179 Q-6)"
5961
+ },
5837
5962
  // multiple public variations. Origin: `*_variation.multiple_public`.
5838
5963
  "VAL-PLN-06": {
5839
5964
  id: "VAL-PLN-06",
5840
5965
  severity: "error_draft",
5841
5966
  message: "Only one public variation is allowed per billing period and segment.",
5842
5967
  specRef: "config-validation.md \xA75.3 (provisional \u2014 plan 73 Q-1)"
5968
+ },
5969
+ // more-than-two CTAs on a payload surface. Promoted from §5.8 (plan 174
5970
+ // TASK-7 / devkit #584): the decision output carries ONE cta_path (from
5971
+ // ctas[0]); ctas[1] contributes secondary_cta_label only; ctas[2..] are
5972
+ // dropped at resolution with no finding.
5973
+ "VAL-PLC-05": {
5974
+ id: "VAL-PLC-05",
5975
+ severity: "warning",
5976
+ message: "Payload '{payload}' authors {count} CTAs, but the decision output carries one primary path and one secondary label \u2014 the third and later CTAs are dropped at resolution.",
5977
+ specRef: "config-validation.md \xA75.8 (promoted \u2014 plan 174 TASK-7)"
5978
+ },
5979
+ // widest-possible-audience trial rule. Promoted from §5.8 (plan 174 TASK-7 /
5980
+ // devkit #584): plan and segment on a free trial rule NARROW, so null on
5981
+ // both means every user on every plan — legal and occasionally intended,
5982
+ // but indistinguishable from an unfinished rule after authoring. Reverse
5983
+ // trial rules can't hit this (premium_plan_id is required).
5984
+ "VAL-TRL-04": {
5985
+ id: "VAL-TRL-04",
5986
+ severity: "warning",
5987
+ message: "Trial rule '{rule}' targets every user on every plan (no plan, no segment). Confirm the widest possible audience is intended.",
5988
+ specRef: "config-validation.md \xA75.8 (promoted \u2014 plan 174 TASK-7)"
5843
5989
  }
5844
5990
  };
5845
5991
  function getCatalogEntry(id) {
@@ -5849,9 +5995,85 @@ function runSemanticRules(graph) {
5849
5995
  return [
5850
5996
  ...checkPlansHaveStripePrice(graph),
5851
5997
  ...checkRuleOverlaps(graph),
5852
- ...checkPublicVariationCollisions(graph)
5998
+ ...checkLimitRuleEnforcement(graph),
5999
+ ...checkPublicVariationCollisions(graph),
6000
+ ...checkPayloadCtaOverflow(graph),
6001
+ ...checkTrialRuleWidestAudience(graph)
5853
6002
  ];
5854
6003
  }
6004
+ function checkLimitRuleEnforcement(graph) {
6005
+ const findings = [];
6006
+ const CAP_FIELDS = ["limit_value", "allowance_value", "included_count"];
6007
+ for (const rule of graph.entitlement_rules ?? []) {
6008
+ if (rule.enforcement !== void 0 && rule.enforcement !== null) continue;
6009
+ const cappedField = CAP_FIELDS.find((f) => typeof rule[f] === "number" && Number.isFinite(rule[f]));
6010
+ if (!cappedField) continue;
6011
+ const id = String(rule.handle ?? rule.id ?? "");
6012
+ const name = String(rule.name ?? id);
6013
+ findings.push(
6014
+ finding(
6015
+ "VAL-PLN-07",
6016
+ { object_type: "entitlement_rule", object_id: id, field: "enforcement", studio: "plans-entitlements" },
6017
+ {
6018
+ message: `Limit rule '${name}' sets no enforcement \u2014 at the cap it blocks by default. Set enforcement explicitly (hard_block, soft_block, degrade, allow_overage) if that isn't the intent.`
6019
+ }
6020
+ )
6021
+ );
6022
+ }
6023
+ return findings;
6024
+ }
6025
+ function surfaceCtas(surface) {
6026
+ if (!surface || typeof surface !== "object") return 0;
6027
+ const ctas = surface.ctas;
6028
+ return Array.isArray(ctas) ? ctas.length : 0;
6029
+ }
6030
+ function checkPayloadCtaOverflow(graph) {
6031
+ const findings = [];
6032
+ const flag = (payloadId, count, objectType) => {
6033
+ findings.push(
6034
+ finding("VAL-PLC-05", { object_type: objectType, object_id: payloadId, field: "ctas", studio: "placements" }, {
6035
+ message: `Payload '${payloadId}' authors ${count} CTAs, but the decision output carries one primary path and one secondary label \u2014 the third and later CTAs are dropped at resolution.`
6036
+ })
6037
+ );
6038
+ };
6039
+ for (const placement of graph.placements ?? []) {
6040
+ const payloads = Array.isArray(placement.payloads) ? placement.payloads : [];
6041
+ for (const payload of payloads) {
6042
+ const payloadId = String(payload.id ?? placement.id ?? "");
6043
+ const surfaces = Array.isArray(payload.surfaces) ? payload.surfaces : [];
6044
+ for (const surface of surfaces) {
6045
+ const count = surfaceCtas(surface);
6046
+ if (count > 2) flag(payloadId, count, "placement_payload");
6047
+ }
6048
+ }
6049
+ }
6050
+ for (const payload of graph.placement_payloads ?? []) {
6051
+ const payloadId = String(payload.payload_id ?? payload.id ?? "");
6052
+ const surfaces = Array.isArray(payload.surfaces) ? payload.surfaces : [];
6053
+ for (const surface of surfaces) {
6054
+ const count = surfaceCtas(surface);
6055
+ if (count > 2) flag(payloadId, count, "placement_payload");
6056
+ }
6057
+ }
6058
+ return findings;
6059
+ }
6060
+ function checkTrialRuleWidestAudience(graph) {
6061
+ const findings = [];
6062
+ for (const rule of graph.free_trial_rules ?? []) {
6063
+ const planId = rule.plan_id;
6064
+ const segmentId = rule.segment_id;
6065
+ const planUnset = planId === null || planId === void 0 || planId === "";
6066
+ const segmentUnset = segmentId === null || segmentId === void 0 || segmentId === "";
6067
+ if (!planUnset || !segmentUnset) continue;
6068
+ const ruleId = String(rule.handle ?? rule.id ?? "");
6069
+ findings.push(
6070
+ finding("VAL-TRL-04", { object_type: "free_trial_rule", object_id: ruleId, studio: "trials" }, {
6071
+ message: `Trial rule '${ruleId || "unnamed"}' targets every user on every plan (no plan, no segment). Confirm the widest possible audience is intended.`
6072
+ })
6073
+ );
6074
+ }
6075
+ return findings;
6076
+ }
5855
6077
  function finding(catalogId, target, opts = {}) {
5856
6078
  const entry = getCatalogEntry(catalogId);
5857
6079
  const severity = entry?.severity ?? "warning";
@@ -5915,6 +6137,7 @@ function checkRuleOverlaps(graph) {
5915
6137
  const sigs = [];
5916
6138
  for (const rule of rules) {
5917
6139
  const id = String(rule.handle ?? rule.id ?? "");
6140
+ const entitlementId = typeof rule.entitlement_id === "string" ? rule.entitlement_id : "";
5918
6141
  const targetIds = /* @__PURE__ */ new Set();
5919
6142
  if (Array.isArray(rule.targets)) {
5920
6143
  for (const t of rule.targets) {
@@ -5942,6 +6165,7 @@ function checkRuleOverlaps(graph) {
5942
6165
  sigs.push({
5943
6166
  rule,
5944
6167
  id,
6168
+ entitlementId,
5945
6169
  targetIds,
5946
6170
  segmentPairs,
5947
6171
  matchesAllSegments: segmentIds.length === 0
@@ -5952,6 +6176,7 @@ function checkRuleOverlaps(graph) {
5952
6176
  for (let j = i + 1; j < sigs.length; j++) {
5953
6177
  const a = sigs[i];
5954
6178
  const b = sigs[j];
6179
+ if (!a.entitlementId || a.entitlementId !== b.entitlementId) continue;
5955
6180
  let sharedTarget = false;
5956
6181
  for (const t of a.targetIds) {
5957
6182
  if (b.targetIds.has(t)) {
@@ -5990,7 +6215,7 @@ function checkRuleOverlaps(graph) {
5990
6215
  studio: "plans-entitlements"
5991
6216
  },
5992
6217
  {
5993
- message: `Entitlement rule '${name}' overlaps another rule on a shared target and segment \u2014 only one will apply.`,
6218
+ message: `Entitlement rule '${name}' overlaps another rule for the same entitlement on a shared target and segment \u2014 only one will apply.`,
5994
6219
  detail: "Where rules overlap, the most permissive value applies (plans-entitlements-studio-ui.md \xA72.3.2). Adjust the segment selection if this is unintended."
5995
6220
  }
5996
6221
  )
@@ -6055,8 +6280,12 @@ function messageForZodIssue(issue) {
6055
6280
  switch (issue.code) {
6056
6281
  case "invalid_type":
6057
6282
  return issue.input === void 0 ? `${field} is required.` : `${field} must be a ${issue.expected ?? "valid value"}.`;
6058
- case "invalid_value":
6059
- return `${field} must be one of the allowed values.`;
6283
+ case "invalid_value": {
6284
+ const values = (issue.values ?? []).filter(
6285
+ (v) => ["string", "number", "boolean"].includes(typeof v)
6286
+ );
6287
+ return values.length > 0 ? `${field} must be one of: ${values.map((v) => `'${String(v)}'`).join(", ")}.` : `${field} must be one of the allowed values.`;
6288
+ }
6060
6289
  case "invalid_format":
6061
6290
  return `${field} isn't in a valid format.`;
6062
6291
  case "too_small":
@@ -6116,7 +6345,12 @@ var DataClassification2 = {
6116
6345
  Financial: { "x-revturbine-data-classification": "financial" },
6117
6346
  Unrestricted: { "x-revturbine-data-classification": "unrestricted" }
6118
6347
  };
6348
+ var SCHEMA_EXPOSURE_META_KEY2 = "x-revturbine-schema-exposure";
6119
6349
  var READ_ONLY_META_KEY2 = "readOnly";
6350
+ var DECISION_ONLY_META_KEY2 = "x-revturbine-decision-only";
6351
+ var DecisionOnly2 = { [DECISION_ONLY_META_KEY2]: true };
6352
+ var ClientSafe2 = { [SCHEMA_EXPOSURE_META_KEY2]: SchemaExposure2.External };
6353
+ var ServerOnly2 = { [SCHEMA_EXPOSURE_META_KEY2]: SchemaExposure2.Internal };
6120
6354
  function toWritableSchema2(schema) {
6121
6355
  const writableShape = {};
6122
6356
  for (const [fieldName, fieldSchema] of Object.entries(schema.shape)) {
@@ -6140,7 +6374,7 @@ function toCreateSchema2(schema) {
6140
6374
  }
6141
6375
  var { Unrestricted: Unrestricted24 } = DataClassification2;
6142
6376
  var { Transient: Transient22, Persisted: Persisted24 } = SchemaPersistence2;
6143
- var { Internal: Internal20, External: External13 } = SchemaExposure2;
6377
+ var { Internal: Internal21, External: External13 } = SchemaExposure2;
6144
6378
  var PaginationParamsSchema2 = z32.object({
6145
6379
  page: z32.coerce.number().int().min(1).default(1).meta(Unrestricted24),
6146
6380
  per_page: z32.coerce.number().int().min(1).max(100).default(25).meta(Unrestricted24)
@@ -6176,7 +6410,7 @@ var TenantIdField2 = z32.object({
6176
6410
  {
6177
6411
  id: "null",
6178
6412
  "x-revturbine-schema-persistence": Transient22,
6179
- "x-revturbine-schema-exposure": Internal20
6413
+ "x-revturbine-schema-exposure": Internal21
6180
6414
  }
6181
6415
  );
6182
6416
  var BillingCadenceSchema2 = z32.enum([
@@ -6242,7 +6476,7 @@ var FeatureFlagValueSchema2 = z32.union([
6242
6476
  {
6243
6477
  id: "FeatureFlagValue",
6244
6478
  "x-revturbine-schema-persistence": Transient22,
6245
- "x-revturbine-schema-exposure": Internal20
6479
+ "x-revturbine-schema-exposure": Internal21
6246
6480
  }
6247
6481
  );
6248
6482
  var NameField2 = z32.string().min(1).max(200);
@@ -6253,7 +6487,7 @@ var ThresholdPercentField2 = z32.number().int().min(10).max(100).multipleOf(10);
6253
6487
  var NullableDatetimeField2 = z32.string().datetime().nullable().default(null);
6254
6488
  var AnchorFields2 = z32.object({
6255
6489
  environment_id: z32.string().min(1).default("production").meta({ ...Unrestricted24, readOnly: true })
6256
- }).meta({ id: "null", "x-revturbine-schema-persistence": Transient22, "x-revturbine-schema-exposure": Internal20 });
6490
+ }).meta({ id: "null", "x-revturbine-schema-persistence": Transient22, "x-revturbine-schema-exposure": Internal21 });
6257
6491
  var VersionFields2 = z32.object({
6258
6492
  // Which playbook version (the review/deploy unit — was `change_set_id`) staged
6259
6493
  // this ledger row; null once it is the deployed live row.
@@ -6266,7 +6500,7 @@ var VersionFields2 = z32.object({
6266
6500
  // so a stale draft is detected when live has moved past it.
6267
6501
  sequence: z32.number().int().min(1).default(1).meta({ ...Unrestricted24, readOnly: true }),
6268
6502
  base_sequence: z32.number().int().nullable().default(null).meta({ ...Unrestricted24, readOnly: true })
6269
- }).meta({ id: "null", "x-revturbine-schema-persistence": Transient22, "x-revturbine-schema-exposure": Internal20 });
6503
+ }).meta({ id: "null", "x-revturbine-schema-persistence": Transient22, "x-revturbine-schema-exposure": Internal21 });
6270
6504
  var AnchorBaseSchema2 = IdField2.merge(TimestampFields2).merge(TenantIdField2).merge(AnchorFields2).extend({
6271
6505
  handle: HandleField2.meta({ ...Unrestricted24, readOnly: true }),
6272
6506
  active: z32.boolean().default(true).meta({ ...Unrestricted24, readOnly: true })
@@ -6275,10 +6509,10 @@ function makeAnchor2(id) {
6275
6509
  return AnchorBaseSchema2.meta({
6276
6510
  id,
6277
6511
  "x-revturbine-schema-persistence": Persisted24,
6278
- "x-revturbine-schema-exposure": Internal20
6512
+ "x-revturbine-schema-exposure": Internal21
6279
6513
  });
6280
6514
  }
6281
- var SeveritySchema22 = z32.enum(["info", "warning", "critical"]).meta({ id: "Severity", "x-revturbine-schema-persistence": Transient22, "x-revturbine-schema-exposure": Internal20 });
6515
+ var SeveritySchema22 = z32.enum(["info", "warning", "critical"]).meta({ id: "Severity", "x-revturbine-schema-persistence": Transient22, "x-revturbine-schema-exposure": Internal21 });
6282
6516
  var StudioSurfaceTypeSchema2 = z32.enum([
6283
6517
  "button",
6284
6518
  "plans_page_ctas",
@@ -6299,7 +6533,7 @@ var StudioSurfaceTypeSchema2 = z32.enum([
6299
6533
  "cli",
6300
6534
  "agent_connector",
6301
6535
  "custom_in_app"
6302
- ]).meta({ id: "StudioSurfaceType", "x-revturbine-schema-persistence": Transient22, "x-revturbine-schema-exposure": Internal20 });
6536
+ ]).meta({ id: "StudioSurfaceType", "x-revturbine-schema-persistence": Transient22, "x-revturbine-schema-exposure": Internal21 });
6303
6537
  var CtaActionTypeSchema2 = z32.enum([
6304
6538
  "open_checkout",
6305
6539
  "view_plans",
@@ -7179,7 +7413,7 @@ var trialPaths2 = {
7179
7413
  })
7180
7414
  }
7181
7415
  };
7182
- var { Unrestricted: Unrestricted42, Financial: Financial4 } = DataClassification2;
7416
+ var { Unrestricted: Unrestricted42, Financial: Financial5 } = DataClassification2;
7183
7417
  var { Persisted: Persisted42, Transient: Transient42 } = SchemaPersistence2;
7184
7418
  var { External: External32 } = SchemaExposure2;
7185
7419
  var PLAYBOOK_SDK_FACETS32 = schemaFacets2(SchemaContext2.Playbook, { sdkInput: true });
@@ -7234,7 +7468,7 @@ var PlanVariationSchema2 = IdField2.merge(TimestampFields2).merge(TenantIdField2
7234
7468
  plan_id: z82.string().min(1).meta(Unrestricted42),
7235
7469
  billing_period: z82.enum(["monthly", "annual", "one_time", "custom"]).meta(Unrestricted42),
7236
7470
  segment_id: z82.string().nullable().default(null).meta(Unrestricted42),
7237
- price_amount: z82.number().min(0).meta(Financial4),
7471
+ price_amount: z82.number().min(0).meta(Financial5),
7238
7472
  pricing_model: PricingModelSchema2.meta(Unrestricted42),
7239
7473
  visibility: PlanVisibilitySchema2.default("public").meta(Unrestricted42),
7240
7474
  // Soft reference → StripePrice.stripe_price_id (the backend Stripe-price mirror).
@@ -7279,7 +7513,7 @@ var AddOnVariationSchema2 = IdField2.merge(TimestampFields2).merge(TenantIdField
7279
7513
  // expansion packages) bind here without coercion to 'custom'.
7280
7514
  billing_period: z82.enum(["monthly", "annual", "one_time", "custom"]).meta(Unrestricted42),
7281
7515
  segment_id: z82.string().nullable().default(null).meta(Unrestricted42),
7282
- price_amount: z82.number().min(0).meta(Financial4),
7516
+ price_amount: z82.number().min(0).meta(Financial5),
7283
7517
  pricing_model: PricingModelSchema2.meta(Unrestricted42),
7284
7518
  visibility: PlanVisibilitySchema2.default("public").meta(Unrestricted42),
7285
7519
  // Soft reference → StripePrice.stripe_price_id (the backend Stripe-price mirror).
@@ -7306,8 +7540,8 @@ var StripePriceSchema2 = IdField2.merge(TimestampFields2).merge(TenantIdField2).
7306
7540
  stripe_price_id: z82.string().min(1).meta(Unrestricted42),
7307
7541
  stripe_product_id: z82.string().min(1).meta(Unrestricted42),
7308
7542
  billing_period: StripePriceBillingPeriodSchema2.meta(Unrestricted42),
7309
- unit_amount_cents: z82.number().int().min(0).nullable().default(null).meta(Financial4),
7310
- currency: CurrencySchema2.meta(Financial4),
7543
+ unit_amount_cents: z82.number().int().min(0).nullable().default(null).meta(Financial5),
7544
+ currency: CurrencySchema2.meta(Financial5),
7311
7545
  pricing_model: PricingModelSchema2.meta(Unrestricted42),
7312
7546
  nickname: z82.string().nullable().default(null).meta(Unrestricted42),
7313
7547
  // Placeholder/seed price (demo or pre-integration tenants) vs a real
@@ -7790,6 +8024,10 @@ var PlacementTestModeSchema2 = z92.enum(["off", "test_users", "all_traffic"]).me
7790
8024
  var PlacementSettingsCapStateSchema2 = z92.object({
7791
8025
  capRules: z92.array(PlacementSettingsCapRuleSchema2).default([]).meta(Unrestricted52),
7792
8026
  sessionCooldownMinutes: z92.number().int().min(0).default(30).meta(Unrestricted52),
8027
+ // Tenant-level default remind-me-later (defer) window, in minutes. A
8028
+ // per-payload `remind_later_minutes` overrides it when set (plan 167 REQ-6,
8029
+ // Q-3). Rides in this global_frequency_cap jsonb wrapper — no column/`.fbs`.
8030
+ remindLaterMinutes: z92.number().int().min(0).default(60).meta(Unrestricted52),
7793
8031
  testMode: PlacementTestModeSchema2.default("off").meta(Unrestricted52)
7794
8032
  }).meta(
7795
8033
  { id: "PlacementSettingsCapState", "x-revturbine-schema-persistence": Transient52, "x-revturbine-schema-exposure": Internal42 }
@@ -7804,7 +8042,8 @@ var PlacementSettingsSchema2 = IdField2.merge(TimestampFields2).merge(TenantIdFi
7804
8042
  global_frequency_cap_period: z92.enum(["hour", "day", "week", "month", "session"]).nullable().default(null).meta(Unrestricted52),
7805
8043
  suppress_for_paid: z92.boolean().default(false).meta(Unrestricted52),
7806
8044
  suppress_for_trial: z92.boolean().default(false).meta(Unrestricted52),
7807
- default_dismiss_cooldown_hours: z92.number().int().min(0).default(24).meta(Unrestricted52),
8045
+ // `default_dismiss_cooldown_hours` removed (plan 167 Q-2): the dismiss
8046
+ // cooldown is defined per-payload in days (`cooldown_after_dismiss_days`).
7808
8047
  allow_stacking: z92.boolean().default(false).meta(Unrestricted52),
7809
8048
  priority_collision_strategy: z92.enum(["highest_priority", "most_recent", "random"]).default("highest_priority").meta(Unrestricted52)
7810
8049
  }).meta(
@@ -7916,7 +8155,7 @@ var RevTurbineConfigPlacementSettingsItemSchema2 = z92.object({
7916
8155
  global_frequency_cap_period: z92.enum(["hour", "day", "week", "month", "session"]).nullable().default(null).meta(Unrestricted52),
7917
8156
  suppress_for_paid: z92.boolean().default(false).meta(Unrestricted52),
7918
8157
  suppress_for_trial: z92.boolean().default(false).meta(Unrestricted52),
7919
- default_dismiss_cooldown_hours: z92.number().int().min(0).nullable().default(null).meta(Unrestricted52),
8158
+ // `default_dismiss_cooldown_hours` removed (plan 167 Q-2).
7920
8159
  allow_stacking: z92.boolean().default(false).meta(Unrestricted52),
7921
8160
  priority_collision_strategy: z92.string().nullable().default(null).meta(Unrestricted52)
7922
8161
  }).meta(
@@ -8058,7 +8297,11 @@ var RevTurbineConfigUiPathActionTypeSchema2 = z92.enum([
8058
8297
  "verify_work_email",
8059
8298
  "update_payment_method",
8060
8299
  "enable_auto_renewal",
8061
- "manage_subscription"
8300
+ "manage_subscription",
8301
+ // Authored `snooze` resolves through to the SDK's remind-later path
8302
+ // (plan 167 windows); previously it fell through as an invalid type
8303
+ // (plan 174 TASK-6 / Q-5, spec-check F-65a).
8304
+ "snooze"
8062
8305
  ]).meta(
8063
8306
  { id: "RevTurbineConfigUiPathActionType", "x-revturbine-schema-persistence": Transient52, "x-revturbine-schema-exposure": External42 }
8064
8307
  );
@@ -8167,6 +8410,8 @@ var RevTurbineConfigStudioPayloadSchema2 = z92.object({
8167
8410
  caps: RevTurbineConfigStudioPayloadCapsSchema2.optional().meta(Unrestricted52),
8168
8411
  // Optional slot targeting (spec §3.1.1): empty/absent = any compatible slot.
8169
8412
  surface_slot_ids: z92.array(z92.string()).optional().meta(Unrestricted52),
8413
+ // Per-payload remind-me-later override (minutes); absent = inherit tenant default (plan 167 Q-3).
8414
+ remind_later_minutes: z92.number().int().min(0).nullable().optional().meta(Unrestricted52),
8170
8415
  created_at: z92.string().optional().meta({ ...Unrestricted52, readOnly: true }),
8171
8416
  recommendation_strategy: z92.enum(["next_tier_up", "best_value", "custom"]).optional().default("next_tier_up").meta(Unrestricted52),
8172
8417
  recommendation_plan_override: z92.string().optional().meta(Unrestricted52)
@@ -8206,6 +8451,8 @@ var RevTurbineConfigPlacementPayloadItemSchema2 = z92.object({
8206
8451
  placement_id: z92.string().min(1).meta(Unrestricted52),
8207
8452
  target: RevTurbineConfigStudioPayloadTargetSchema2.meta(Unrestricted52),
8208
8453
  caps: RevTurbineConfigStudioPayloadCapsSchema2.optional().meta(Unrestricted52),
8454
+ // Per-payload remind-me-later override (minutes); absent = inherit tenant default (plan 167 Q-3).
8455
+ remind_later_minutes: z92.number().int().min(0).nullable().optional().meta(Unrestricted52),
8209
8456
  created_at: z92.string().meta({ ...Unrestricted52, readOnly: true }),
8210
8457
  updated_at: z92.string().datetime().optional().meta({ ...Unrestricted52, readOnly: true }),
8211
8458
  source_mode: z92.enum(["inline", "content_linked"]).meta(Unrestricted52),
@@ -8436,6 +8683,12 @@ var PlaybookSchema2 = z92.preprocess(normalizeConfigHeaderInput2, PlaybookObject
8436
8683
  "x-revturbine-schema-exposure": External42,
8437
8684
  ...PLAYBOOK_SDK_FACETS42
8438
8685
  });
8686
+ var PlaybookStrictSchema2 = z92.preprocess(normalizeConfigHeaderInput2, PlaybookObjectSchema2.strict()).meta({
8687
+ id: "PlaybookStrict",
8688
+ "x-revturbine-schema-persistence": Transient52,
8689
+ "x-revturbine-schema-exposure": External42,
8690
+ ...PLAYBOOK_SDK_FACETS42
8691
+ });
8439
8692
  var configPaths2 = {
8440
8693
  "/api/seat-type-anchors": {
8441
8694
  get: operation2({
@@ -8711,7 +8964,7 @@ function repairDeprecatedFields(config, schema = PlaybookObjectSchema2) {
8711
8964
  }
8712
8965
 
8713
8966
  // src/schema/version.ts
8714
- var SCHEMA_VERSION = "0.1.145";
8967
+ var SCHEMA_VERSION = "0.1.168";
8715
8968
 
8716
8969
  // src/lib/credentials.ts
8717
8970
  import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";