Files
zeekay bc4ddf332b chore: rebase the tree onto upstream master fa1a9a60
Mechanically re-derived: bin/debrand runs over a fresh import of
posthog/posthog@fa1a9a60d4 (2026-08-06).
The pipeline (.hanzo/workflows), the Dockerfiles and bin/docker*
entrypoints, compose files, LLM.md and the squashed initial migration
are restored from the shipped tree, same as the previous import.

The prune's import-closure guard kept 21 products the new core now
imports; dropping them is a refactor now, recorded rather than forced.
2026-08-06 01:25:36 -07:00

214 lines
9.9 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Standard Subscription serializer.",
"properties": {
"ai_prompt_config": {
"description": "Configuration for AI report subscriptions (analysis window, future knobs). Only valid when resource_type is 'ai_prompt'. Replaced wholesale on writes.",
"properties": {
"window": {
"description": "Analysis window for the report. Omitted = 'since_last_sent' (everything since the previous scheduled delivery).",
"properties": {
"end_days_ago": {
"anyOf": [
{
"maximum": 365,
"minimum": 0,
"type": "number"
},
{
"type": "null"
}
],
"description": "Upper bound of the analysis window, in days before the run (0 = now). Required for 'days_ago_range' and must be less than start_days_ago; ignored for other modes. 0-365."
},
"mode": {
"default": "since_last_sent",
"description": "What the report analyzes each run:\n* `since_last_sent` (default) — everything since the previous successful scheduled delivery (gap-free; test/manual sends don't move the anchor)\n* `last_n_days` — a fixed trailing window of start_days_ago days\n* `days_ago_range` — the explicit range from start_days_ago to end_days_ago days ago\n\n* `since_last_sent` - Since last report\n* `last_n_days` - Last N days\n* `days_ago_range` - Between X and Y days ago",
"enum": ["since_last_sent", "last_n_days", "days_ago_range"],
"type": "string"
},
"start_days_ago": {
"anyOf": [
{
"maximum": 365,
"minimum": 1,
"type": "number"
},
{
"type": "null"
}
],
"description": "Lower bound of the analysis window, in days before the run. Required for 'last_n_days' (the N) and 'days_ago_range'; ignored for 'since_last_sent'. 1-365."
}
},
"type": "object"
}
},
"type": "object"
},
"bysetpos": {
"anyOf": [
{
"maximum": 2147483647,
"minimum": -2147483648,
"type": "number"
},
{
"type": "null"
}
],
"description": "Position within byweekday set for monthly frequency (e.g. 1 for first, -1 for last)."
},
"byweekday": {
"anyOf": [
{
"items": {
"description": "* `monday` - Monday\n* `tuesday` - Tuesday\n* `wednesday` - Wednesday\n* `thursday` - Thursday\n* `friday` - Friday\n* `saturday` - Saturday\n* `sunday` - Sunday",
"enum": ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"],
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"description": "Days of week for daily or weekly subscriptions: monday, tuesday, wednesday, thursday, friday, saturday, sunday."
},
"count": {
"anyOf": [
{
"maximum": 2147483647,
"minimum": -2147483648,
"type": "number"
},
{
"type": "null"
}
],
"description": "Total number of deliveries before the subscription stops. Null for unlimited."
},
"dashboard": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "Dashboard ID to subscribe to (mutually exclusive with insight on create)."
},
"dashboard_export_insights": {
"description": "List of insight IDs from the dashboard to include. Required for dashboard subscriptions, max 10.",
"items": {
"type": "number"
},
"type": "array"
},
"enabled": {
"description": "Whether the subscription is active. Set to false to pause delivery without deleting. Auto-set to false when the delivery integration becomes invalid.",
"type": "boolean"
},
"frequency": {
"description": "How often to deliver: daily, weekly, monthly, or yearly.\n\n* `daily` - Daily\n* `weekly` - Weekly\n* `monthly` - Monthly\n* `yearly` - Yearly",
"enum": ["daily", "weekly", "monthly", "yearly"],
"type": "string"
},
"insight": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "Insight ID to subscribe to (mutually exclusive with dashboard on create)."
},
"integration_id": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "ID of a connected Slack integration. Required when target_type is slack."
},
"interval": {
"description": "Interval multiplier (e.g. 2 with weekly frequency means every 2 weeks). Required on create; must be 1 or greater.",
"maximum": 2147483647,
"minimum": 1,
"type": "number"
},
"prompt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Free-text prompt that drives the AI-generated report. Required when resource_type is 'ai_prompt'. Max 4000 characters."
},
"send_test_now": {
"description": "Whether to immediately deliver the subscription once on save so the editor can confirm it looks right. Defaults to true on create. When omitted on update, a delivery is sent only if the edit changed what gets delivered (recipient, channel, source) or re-enabled the subscription. The recurring schedule is unaffected.",
"type": "boolean"
},
"start_date": {
"description": "When to start delivering (ISO 8601 datetime).",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"type": "string"
},
"summary_enabled": {
"description": "Whether to attach an AI-generated summary to each delivery (insight and dashboard subscriptions only). Requires the organization to have approved AI data processing, and is subject to the org's active-summary cap and AI credit budget; otherwise the write is rejected. Not applicable to prompt subscriptions, which are themselves AI-generated.",
"type": "boolean"
},
"summary_prompt_guide": {
"description": "Optional free-text guidance (max 500 chars) steering the AI summary, e.g. which metrics to emphasize. Only settable when AI summary context is enabled for the organization; clearing it (empty string) is always allowed.",
"maxLength": 500,
"type": "string"
},
"target_type": {
"description": "Delivery channel: email or slack.\n\n* `email` - Email\n* `slack` - Slack",
"enum": ["email", "slack"],
"type": "string"
},
"target_value": {
"description": "Recipient(s): comma-separated email addresses for email, or Slack channel name/ID for slack.",
"type": "string"
},
"title": {
"anyOf": [
{
"maxLength": 100,
"type": "string"
},
{
"type": "null"
}
],
"description": "Human-readable name for this subscription."
},
"until_date": {
"anyOf": [
{
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"type": "string"
},
{
"type": "null"
}
],
"description": "When to stop delivering (ISO 8601 datetime). Null for indefinite."
}
},
"required": ["target_type", "target_value", "frequency", "interval", "start_date"],
"type": "object"
}