@koda-sl/baker-cli 0.504.0 → 0.506.0
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.
- package/README.md +3 -0
- package/dist/{ads-MAPZYX6F.js → ads-T5RPISTB.js} +3 -3
- package/dist/{analytics-4CCQYY7Z.js → analytics-P5UFA6I4.js} +315 -18
- package/dist/analytics-P5UFA6I4.js.map +1 -0
- package/dist/{chunk-DI44SZVP.js → chunk-7J3NZBPV.js} +31 -1
- package/dist/chunk-7J3NZBPV.js.map +1 -0
- package/dist/{chunk-VU5Z2V4S.js → chunk-D3KLDIPQ.js} +2 -2
- package/dist/{chunk-GJCB46L6.js → chunk-HWDRW36T.js} +2 -2
- package/dist/{chunk-S3FFLLYF.js → chunk-LIRX2Q66.js} +2 -2
- package/dist/{chunk-DX46OE4U.js → chunk-OJGYYH6K.js} +2 -2
- package/dist/{chunk-ZEGNIP3Y.js → chunk-TVTSA4EN.js} +3 -3
- package/dist/cli.js +3 -3
- package/dist/{funnel-727XATM5.js → funnel-S6JTLUK6.js} +3 -3
- package/dist/{google-VPL4KZDP.js → google-3GSINSOV.js} +2 -2
- package/dist/{lookup-LWJMDEEL.js → lookup-ZJIP2M4X.js} +4 -4
- package/dist/{performance-CIUVIFD7.js → performance-WPFGEJTE.js} +13 -3
- package/dist/performance-WPFGEJTE.js.map +1 -0
- package/dist/{plan-O2TTEUIW.js → plan-TVQSEKYL.js} +6 -6
- package/dist/{questionnaire-VE42SW77.js → questionnaire-LEZJLMAV.js} +3 -3
- package/dist/{sends-OLVQGOAE.js → sends-6FI7WELX.js} +3 -3
- package/dist/{sources-PSM2A5QD.js → sources-L3KNVLIB.js} +4 -4
- package/dist/{unstage-QFVL7AZ4.js → unstage-MDSSPUKV.js} +3 -3
- package/dist/{url-options-LA6BL3GS.js → url-options-IHL4OU4C.js} +2 -2
- package/package.json +1 -1
- package/dist/analytics-4CCQYY7Z.js.map +0 -1
- package/dist/chunk-DI44SZVP.js.map +0 -1
- package/dist/performance-CIUVIFD7.js.map +0 -1
- /package/dist/{ads-MAPZYX6F.js.map → ads-T5RPISTB.js.map} +0 -0
- /package/dist/{chunk-VU5Z2V4S.js.map → chunk-D3KLDIPQ.js.map} +0 -0
- /package/dist/{chunk-GJCB46L6.js.map → chunk-HWDRW36T.js.map} +0 -0
- /package/dist/{chunk-S3FFLLYF.js.map → chunk-LIRX2Q66.js.map} +0 -0
- /package/dist/{chunk-DX46OE4U.js.map → chunk-OJGYYH6K.js.map} +0 -0
- /package/dist/{chunk-ZEGNIP3Y.js.map → chunk-TVTSA4EN.js.map} +0 -0
- /package/dist/{funnel-727XATM5.js.map → funnel-S6JTLUK6.js.map} +0 -0
- /package/dist/{google-VPL4KZDP.js.map → google-3GSINSOV.js.map} +0 -0
- /package/dist/{lookup-LWJMDEEL.js.map → lookup-ZJIP2M4X.js.map} +0 -0
- /package/dist/{plan-O2TTEUIW.js.map → plan-TVQSEKYL.js.map} +0 -0
- /package/dist/{questionnaire-VE42SW77.js.map → questionnaire-LEZJLMAV.js.map} +0 -0
- /package/dist/{sends-OLVQGOAE.js.map → sends-6FI7WELX.js.map} +0 -0
- /package/dist/{sources-PSM2A5QD.js.map → sources-L3KNVLIB.js.map} +0 -0
- /package/dist/{unstage-QFVL7AZ4.js.map → unstage-MDSSPUKV.js.map} +0 -0
- /package/dist/{url-options-LA6BL3GS.js.map → url-options-IHL4OU4C.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../api/src/ads-performance/accounts.ts","../../api/src/ads-performance/wire.ts","../../api/src/ads-performance/currency.ts","../../api/src/ads-performance/attention.ts","../../api/src/ads-performance/changeWords.ts","../../api/src/ads-performance/creativeAssets.ts","../../api/src/ads-performance/creativeHealth.ts","../../api/src/ads-performance/diagnostic.ts","../../api/src/ads-performance/health.ts","../../api/src/ads-performance/library.ts","../../api/src/ads-performance/liveIn.ts","../../api/src/ads-performance/people.ts","../../api/src/ads-performance/search.ts","../../api/src/ads-performance/setup.ts","../../api/src/ads-performance/targets.ts","../../api/src/ads-performance/resultNoun.ts","../src/commands/ads/performance/index.ts","../src/commands/ads/performance/args.ts","../src/commands/ads/performance/goalWrites.ts","../src/commands/ads/performance/reportCommand.ts","../src/commands/ads/performance/library.ts","../src/commands/ads/performance/report.ts","../src/commands/ads/performance/accounts.ts","../src/commands/ads/performance/targets.ts","../src/commands/ads/performance/attention.ts","../src/commands/ads/performance/creativeAssets.ts","../src/commands/ads/performance/creativeHealth.ts","../src/commands/ads/performance/currency.ts","../src/commands/ads/performance/diagnostic.ts","../src/commands/ads/performance/health.ts","../src/commands/ads/performance/liveIn.ts","../src/commands/ads/performance/people.ts","../src/commands/ads/performance/progress.ts","../src/commands/ads/performance/search.ts","../src/commands/ads/performance/setup.ts","../src/commands/ads/performance/trend.ts"],"sourcesContent":["/**\n * `baker ads performance accounts` — the Summary's accounts table for the\n * agent: one row per ad account with what it spent and bought, its change\n * against the days before, and where it stands against its own target, plus\n * its cost per result week by week. Read from the same summary the dashboard\n * draws (`convex/adPerformance/accountsSummary.ts`).\n */\n\nimport { z } from \"zod\";\nimport type { AdGoalStatus, AdTargetFocus, AdTargetSource } from \"./targets\";\nimport { adPerformanceScopeFields, scopeRules } from \"./wire\";\n\n/**\n * The grains the dashboard's accounts table reads at (`AdsGranularity`). The\n * change compares whole settled buckets of it, so a week or month grain can\n * say a different change than the day grain over the same window.\n */\nexport const AD_ACCOUNTS_GRANULARITIES = [\"day\", \"week\", \"month\"] as const;\nexport type AdAccountsGranularity = (typeof AD_ACCOUNTS_GRANULARITIES)[number];\n\nexport const adPerformanceAccountsRequestSchema = z\n .object({ ...adPerformanceScopeFields, granularity: z.enum(AD_ACCOUNTS_GRANULARITIES).default(\"day\") })\n .superRefine(scopeRules);\nexport type AdPerformanceAccountsRequest = z.input<typeof adPerformanceAccountsRequestSchema>;\n\n/** One ad account's period. Money in `currency`: the report's, or the account's own where no rate converts it. */\nexport interface AdAccountReportRow {\n platform: string;\n adAccountId: string;\n name: string;\n currency: string;\n spend: number;\n results: number;\n /** Null without results. */\n costPerResult: number | null;\n /** Against as many days just before, as a share (0.2 = +20 %); null where the days before are not in the history. */\n change: { spend: number | null; results: number | null; costPerResult: number | null } | null;\n target: { value: number | null; currency: string | null; metric: AdTargetFocus; source: AdTargetSource } | null;\n /** Where it stands against that target; for a Google account judged by kind of search, the worst of those. */\n status: AdGoalStatus;\n /** Each kind of search's own verdict, for a Google account whose Search targets are split. */\n bySearch: Array<{ search: string; status: AdGoalStatus; costPerResult: number | null }>;\n /**\n * Oldest first, each bucket's first day: weeks (starting Monday) at the day\n * and week grains, months at the month grain; the first and last maybe partial.\n */\n series: Array<{ bucket: string; spend: number; results: number; costPerResult: number | null }>;\n}\n\nexport interface AdPerformanceAccountsData {\n window: { from: string; to: string; days: number };\n granularity: AdAccountsGranularity;\n /** One sentence to tell the person as is. */\n headline: string;\n accounts: AdAccountReportRow[];\n /** Selected accounts that spent nothing in the period: nothing to judge. */\n notSpending: Array<{ platform: string; adAccountId: string; name: string }>;\n}\n","/**\n * Wire contract for `baker ads performance` — the agent's read of the\n * ad-performance store: every connected ad platform's numbers, entities,\n * changes and alerts, synced into Baker so nothing here calls a platform.\n *\n * Requests are zod schemas the backend parses at the boundary\n * (`convex/adPerformance/route.ts`) and the CLI validates before sending.\n * Responses are the `data` of a `{ ok, data }` envelope, typed here once for\n * both sides; the Convex return validators (`adPerformance/reportValidators.ts`)\n * hold the backend to the same shape.\n *\n * Money is never added across currencies: every amount sits beside its\n * `currency`. Ratios are `null` where their denominator is zero.\n */\n\nimport { z } from \"zod\";\nimport { calendarDaySchema, todayUtc } from \"../calendarDays\";\nimport { adReportCurrencySchema } from \"./currency\";\nimport type { AdCreativeLibraryLink } from \"./library\";\nimport type { AdResultNoun } from \"./resultNoun\";\nimport type { AdJudgingTarget } from \"./targets\";\n\nexport const AD_PERFORMANCE_PLATFORMS = [\"meta\", \"google\", \"linkedin\", \"x\", \"chatgpt\"] as const;\nexport type AdPerformancePlatform = (typeof AD_PERFORMANCE_PLATFORMS)[number];\n\nexport const AD_ENTITY_LEVELS = [\"campaign\", \"ad_group\", \"ad\", \"keyword\"] as const;\nexport type AdEntityLevel = (typeof AD_ENTITY_LEVELS)[number];\n\nexport const AD_FUNNEL_LEVELS = [\"campaign\", \"ad_group\", \"ad\"] as const;\n\nexport const AD_ENTITY_SORTS = [\n \"spend\",\n \"impressions\",\n \"clicks\",\n \"link_clicks\",\n \"results\",\n \"result_value\",\n \"cost_per_result\",\n \"ctr\",\n \"first_delivery\",\n \"last_delivery\",\n \"name\",\n] as const;\n\nexport const AD_CHANGE_KIND_NAMES = [\n \"created\",\n \"status\",\n \"budget\",\n \"bid\",\n \"schedule\",\n \"name\",\n \"creative\",\n \"targeting\",\n \"goal\",\n \"removed\",\n \"other\",\n] as const;\n\nexport const AD_CHANGE_SOURCES = [\"baker\", \"platform\", \"observed\"] as const;\nexport const AD_ACTOR_KINDS = [\"person\", \"platform_automatic\", \"baker\", \"unknown\"] as const;\n/** `audience_segment` (new, engaged or existing customers), `age` and `gender` are Meta's only. */\nexport const AD_BREAKDOWN_DIMENSIONS = [\"placement\", \"country\", \"device\", \"audience_segment\", \"age\", \"gender\"] as const;\nexport const AD_SEARCH_TERM_SORTS = [\"spend\", \"clicks\", \"conversions\", \"cost_per_conversion\"] as const;\n/** A Google campaign's brand segment, as requests name it (`AdBrandSegment`). */\nexport const AD_BRAND_SEGMENT_NAMES = [\"brand\", \"competitor\", \"non_brand\", \"other\", \"unsorted\"] as const;\nexport const AD_STATUS_NAMES = [\n \"active\",\n \"paused\",\n \"scheduled\",\n \"ended\",\n \"in_review\",\n \"rejected\",\n \"draft\",\n \"archived\",\n \"removed\",\n \"unknown\",\n] as const;\n\n/** Days a report reads when the caller names no window: the last 30 complete days. */\nexport const AD_PERFORMANCE_DEFAULT_DAYS = 30;\n/** Ad stats are kept 37 months; a window is capped at that. */\nexport const AD_PERFORMANCE_MAX_DAYS = 1130;\n\n// --- Requests ---\n\nexport const idList = z\n .array(\n z\n .string()\n .min(1)\n .regex(/^[^,]+$/, \"ids cannot contain commas\"),\n )\n .max(200);\n\n/**\n * The window and the scope every report shares. `days` counts complete days\n * back from yesterday; `start`/`end` name the days instead (end defaults to\n * yesterday). Empty lists mean \"all\".\n */\nexport const adPerformanceScopeFields = {\n days: z.number().int().min(1).max(AD_PERFORMANCE_MAX_DAYS).optional(),\n start: calendarDaySchema.optional(),\n end: calendarDaySchema.optional(),\n platforms: z.array(z.enum(AD_PERFORMANCE_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n campaignIds: idList.optional(),\n /** Show every amount in this currency (ISO code), or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n};\n\n/** A day `calendarDaySchema` takes: the order of two is compared only when both are. */\nfunction isCalendarDay(value: string | undefined): value is string {\n return value !== undefined && calendarDaySchema.safeParse(value).success;\n}\n\nexport function scopeRules(req: { days?: number; start?: string; end?: string }, ctx: z.RefinementCtx): void {\n if (req.days !== undefined && req.start !== undefined) {\n ctx.addIssue({ code: \"custom\", path: [\"days\"], message: \"pass days or start/end, not both\" });\n }\n if (req.end !== undefined && req.start === undefined) {\n ctx.addIssue({ code: \"custom\", path: [\"end\"], message: \"end needs a start\" });\n }\n if (isCalendarDay(req.start) && isCalendarDay(req.end) && req.end < req.start) {\n ctx.addIssue({ code: \"custom\", path: [\"end\"], message: \"end is before start\" });\n }\n // UTC's today: a company ahead of it is past it already, and one behind it has not reached it, so the store holds nothing later.\n if (isCalendarDay(req.start) && req.start > todayUtc()) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"start\"],\n message: `${req.start} has not happened yet: pick a start on or before today (${todayUtc()}); the last complete day is yesterday`,\n });\n }\n}\n\n/**\n * The latest month a read can be about: the one holding UTC's tomorrow, so on\n * the last day of a month the next one is taken where it has already started\n * (east of UTC). The backend still refuses one its own timezone has not reached.\n */\nfunction latestStartedMonth(): string {\n return new Date(Date.now() + 86_400_000).toISOString().slice(0, 7);\n}\n\n/** `YYYY-MM` of a month that has started: a later one has no days to read. */\nexport const startedMonthSchema = z\n .string()\n .regex(/^\\d{4}-(0[1-9]|1[0-2])$/, \"use YYYY-MM\")\n .refine((month) => month <= latestStartedMonth(), {\n error: (issue) => `${String(issue.input)} has not started yet: pick this month or an earlier one`,\n });\n\nexport const adPerformanceOverviewRequestSchema = z.object(adPerformanceScopeFields).superRefine(scopeRules);\nexport type AdPerformanceOverviewRequest = z.input<typeof adPerformanceOverviewRequestSchema>;\n\n/** `day`, `week` (Monday weeks), `month`, or `total`: one bucket over the whole window. */\nexport const AD_TREND_GRANULARITIES = [\"day\", \"week\", \"month\", \"total\"] as const;\nexport type AdTrendGranularity = (typeof AD_TREND_GRANULARITIES)[number];\n/** `kind` is the campaign's type (Google's channel type); `segment` its brand segment (`AdBrandSegment`, '' off Google). */\nexport const AD_TREND_GROUPS = [\"platform\", \"ad_account\", \"campaign\", \"kind\", \"segment\", \"none\"] as const;\nexport type AdTrendGroup = (typeof AD_TREND_GROUPS)[number];\n\n/** `trend`: the numbers over time, split one way — the read behind the dashboard's charts (`reports.readTrend`). */\nexport const adPerformanceTrendRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n granularity: z.enum(AD_TREND_GRANULARITIES).default(\"day\"),\n groupBy: z.enum(AD_TREND_GROUPS).default(\"platform\"),\n /** With `groupBy: campaign`, the campaigns drawn on their own, by spend; the rest sum into `__other`. */\n limit: z.number().int().min(1).max(50).default(10),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceTrendRequest = z.input<typeof adPerformanceTrendRequestSchema>;\n\nexport const adPerformanceEntitiesRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n level: z.enum(AD_ENTITY_LEVELS).default(\"campaign\"),\n adGroupIds: idList.optional(),\n /** Only these entities, at `level`: the rows a screen already holds, looked up by id. */\n entityIds: idList.optional(),\n statuses: z.array(z.enum(AD_STATUS_NAMES)).optional(),\n search: z.string().max(200).optional(),\n sort: z.enum(AD_ENTITY_SORTS).default(\"spend\"),\n order: z.enum([\"desc\", \"asc\"]).default(\"desc\"),\n limit: z.number().int().min(1).max(500).default(25),\n offset: z.number().int().min(0).default(0),\n includeIdle: z.boolean().default(false),\n /** Compare each row's settled days with as many days before it; also lists what stopped delivering. */\n compare: z.boolean().default(false),\n /** Only campaigns in these brand segments (Google Search: `brand`, `competitor`, `non_brand`; `other`, `unsorted`). */\n segments: z.array(z.enum(AD_BRAND_SEGMENT_NAMES)).optional(),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceEntitiesRequest = z.input<typeof adPerformanceEntitiesRequestSchema>;\n\nexport const adPerformanceEntityRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n platform: z.enum(AD_PERFORMANCE_PLATFORMS),\n level: z.enum(AD_ENTITY_LEVELS),\n entityId: z.string().min(1),\n /** Narrows the lookup of an ad or keyword when known. */\n adGroupId: z.string().min(1).optional(),\n /**\n * Read it over its first to last day of delivery (true) or the period\n * asked (false). Absent: its whole run when it is off or did not deliver\n * in the period.\n */\n wholeRun: z.boolean().optional(),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceEntityRequest = z.input<typeof adPerformanceEntityRequestSchema>;\n\nexport const adPerformanceChangesRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n kinds: z.array(z.enum(AD_CHANGE_KIND_NAMES)).optional(),\n levels: z.array(z.enum([\"account\", ...AD_ENTITY_LEVELS])).optional(),\n entityIds: idList.optional(),\n sources: z.array(z.enum(AD_CHANGE_SOURCES)).optional(),\n actorKinds: z.array(z.enum(AD_ACTOR_KINDS)).optional(),\n limit: z.number().int().min(1).max(500).default(50),\n offset: z.number().int().min(0).default(0),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceChangesRequest = z.input<typeof adPerformanceChangesRequestSchema>;\n\nexport const adPerformanceImpactRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n kinds: z.array(z.enum(AD_CHANGE_KIND_NAMES)).optional(),\n actorKinds: z.array(z.enum(AD_ACTOR_KINDS)).optional(),\n /** Days compared on each side of a change. */\n impactDays: z.number().int().min(3).max(28).default(7),\n limit: z.number().int().min(1).max(200).default(30),\n offset: z.number().int().min(0).default(0),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceImpactRequest = z.input<typeof adPerformanceImpactRequestSchema>;\n\nexport const adPerformanceCreativesRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n groupBy: z.enum([\"creative\", \"ad\"]).default(\"creative\"),\n /** The ads of these ad groups (Meta's ad sets) only. */\n adGroupIds: idList.optional(),\n /** The ads running these pictures or videos only (a creative's `groupKey`): one creative's ads, as its panel reads them. */\n creativeKeys: idList.optional(),\n statuses: z.array(z.enum(AD_STATUS_NAMES)).optional(),\n minSpend: z.number().min(0).default(0),\n minImpressions: z.number().int().min(0).default(1000),\n limit: z.number().int().min(1).max(200).default(25),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceCreativesRequest = z.input<typeof adPerformanceCreativesRequestSchema>;\n\nexport const adPerformanceBreakdownRequestSchema = z\n .object({ ...adPerformanceScopeFields, dimension: z.enum(AD_BREAKDOWN_DIMENSIONS) })\n .superRefine(scopeRules);\nexport type AdPerformanceBreakdownRequest = z.input<typeof adPerformanceBreakdownRequestSchema>;\n\nexport const adPerformanceSearchTermsRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n adGroupIds: idList.optional(),\n minClicks: z.number().int().min(0).default(1),\n /** Only terms with no conversions: the negative-keyword candidates. */\n noResults: z.boolean().default(false),\n search: z.string().max(200).optional(),\n sort: z.enum(AD_SEARCH_TERM_SORTS).default(\"spend\"),\n order: z.enum([\"desc\", \"asc\"]).default(\"desc\"),\n limit: z.number().int().min(1).max(500).default(50),\n offset: z.number().int().min(0).default(0),\n /** Only terms read as these: `brand`, `competitor`, `non_brand`, or `unsorted` (not read yet). */\n termSegments: z.array(z.enum([\"brand\", \"competitor\", \"non_brand\", \"unsorted\"])).optional(),\n /** Only terms bought by campaigns in these segments. */\n campaignSegments: z.array(z.enum(AD_BRAND_SEGMENT_NAMES)).optional(),\n /** Only terms Baker was unsure how to sort: a person's choice settles them. */\n unsureOnly: z.boolean().default(false),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceSearchTermsRequest = z.input<typeof adPerformanceSearchTermsRequestSchema>;\n\nexport const adPerformancePacingRequestSchema = z.object({\n /** Amounts in this currency (ISO code), or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n\n /** `YYYY-MM`, one that has started; the current month when absent. */\n month: startedMonthSchema.optional(),\n platforms: z.array(z.enum(AD_PERFORMANCE_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n});\nexport type AdPerformancePacingRequest = z.input<typeof adPerformancePacingRequestSchema>;\n\nexport const adPerformanceFunnelRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n level: z.enum(AD_FUNNEL_LEVELS).default(\"campaign\"),\n /** Split the visit side by the page each visit entered on. */\n byLanding: z.boolean().default(false),\n limit: z.number().int().min(1).max(2000).default(50),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceFunnelRequest = z.input<typeof adPerformanceFunnelRequestSchema>;\n\nexport const adPerformanceTrackingRequestSchema = z.object(adPerformanceScopeFields).superRefine(scopeRules);\nexport type AdPerformanceTrackingRequest = z.input<typeof adPerformanceTrackingRequestSchema>;\n\nexport const adPerformanceLandingsRequestSchema = z.object(adPerformanceScopeFields).superRefine(scopeRules);\nexport type AdPerformanceLandingsRequest = z.input<typeof adPerformanceLandingsRequestSchema>;\n\n/**\n * `goals`: the conversion actions over the last `days` (90 when none), or over\n * `start`..`end` — both, as the dashboard's Conversions card asks — and the\n * ad accounts in view.\n */\nexport const adPerformanceGoalsRequestSchema = z\n .object({\n /** How far back to look for the conversion actions each platform reported; 90 when neither it nor start/end is named. */\n days: z.number().int().min(7).max(400).optional(),\n start: calendarDaySchema.optional(),\n end: calendarDaySchema.optional(),\n platforms: z.array(z.enum(AD_PERFORMANCE_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n })\n .superRefine((req, ctx) => {\n scopeRules(req, ctx);\n if (req.start !== undefined && req.end === undefined) {\n ctx.addIssue({ code: \"custom\", path: [\"start\"], message: \"start needs an end\" });\n }\n });\nexport type AdPerformanceGoalsRequest = z.input<typeof adPerformanceGoalsRequestSchema>;\n\n/** What \"getting better or worse\" can say about an entity (`convex/adPerformance/diagnosis.ts`). */\nexport const AD_PROGRESS_STATUSES = [\n \"worsening\",\n \"mixed\",\n \"not_comparable\",\n \"steady\",\n \"improving\",\n \"too_early\",\n \"too_little_data\",\n \"stopped\",\n] as const;\nexport type AdProgressStatus = (typeof AD_PROGRESS_STATUSES)[number];\n\n/**\n * `progress`: worst first, per level. The window's end is the \"as of\" day\n * (each platform's last settled day when it ends later); its start, when\n * named, sets how many weeks the sparkline goes back.\n */\nexport const adPerformanceProgressRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n level: z.enum(AD_FUNNEL_LEVELS).default(\"campaign\"),\n statuses: z.array(z.enum(AD_PROGRESS_STATUSES)).optional(),\n limit: z.number().int().min(1).max(200).default(25),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceProgressRequest = z.input<typeof adPerformanceProgressRequestSchema>;\n\nexport const adPerformanceDiagnosisRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n platform: z.enum(AD_PERFORMANCE_PLATFORMS),\n level: z.enum(AD_FUNNEL_LEVELS),\n entityId: z.string().min(1),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceDiagnosisRequest = z.input<typeof adPerformanceDiagnosisRequestSchema>;\n\nexport const adPerformancePulseRequestSchema = z.object({\n /** Amounts in this currency (ISO code), or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n\n platforms: z.array(z.enum(AD_PERFORMANCE_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n});\nexport type AdPerformancePulseRequest = z.input<typeof adPerformancePulseRequestSchema>;\n\n// --- Shared response pieces ---\n\nexport interface AdMetrics {\n spend: number;\n impressions: number;\n clicks: number;\n linkClicks: number;\n engagements: number;\n videoViews: number;\n videoCompletions: number;\n leads: number;\n conversions: number;\n conversionValue: number;\n /** The company's goal actions, else the platform's headline conversions. */\n results: number;\n resultValue: number;\n searchEligibleImpressions: number;\n searchLostImpressionsBudget: number;\n searchLostImpressionsRank: number;\n /** Google Search impressions above the organic results, and first of all; 0 where not measured. */\n searchTopImpressions: number;\n searchAbsoluteTopImpressions: number;\n /** The impressions of the days that measured the two above. */\n searchTopMeasuredImpressions: number;\n /** Google: every conversion action, primary or not, and conversions after a view with no click; 0 where not measured. */\n allConversions: number;\n viewThroughConversions: number;\n /** The headline conversions of the days that measured `allConversions`. */\n allConversionsMeasuredConversions: number;\n /** The sum of each day's reach — never a reach; impressions ÷ it is the average daily frequency. 0 without reach. */\n reach: number;\n /** The impressions of the rows that measured reach: frequency's numerator. */\n reachMeasuredImpressions: number;\n}\n\nexport interface AdRatios {\n ctr: number | null;\n linkCtr: number | null;\n cpc: number | null;\n cpm: number | null;\n costPerResult: number | null;\n resultValuePerSpend: number | null;\n conversionRate: number | null;\n impressionShare: number | null;\n lostShareBudget: number | null;\n lostShareRank: number | null;\n /** Share of Search impressions above the organic results, and first of all, over the days that measured them. */\n topImpressionRate: number | null;\n absoluteTopImpressionRate: number | null;\n /** Every conversion ÷ the counted ones over the same days: well above 1 means uncounted actions fire often. */\n allConversionsPerConversion: number | null;\n /** Video views ÷ impressions, and spend ÷ video views. */\n viewRate: number | null;\n costPerView: number | null;\n /** Impressions ÷ summed daily reach: times the same person saw it in a day, on average. Null without reach. */\n frequency: number | null;\n}\n\n/** Relative changes, `0.1` = +10 %. */\nexport interface AdDeltas {\n spend: number | null;\n impressions: number | null;\n linkClicks: number | null;\n results: number | null;\n resultValue: number | null;\n ctr: number | null;\n cpc: number | null;\n cpm: number | null;\n costPerResult: number | null;\n resultValuePerSpend: number | null;\n conversionRate: number | null;\n}\n\nexport interface AdDayWindow {\n from: string;\n to: string;\n}\n\nexport interface AdReportWindow extends AdDayWindow {\n days: number;\n}\n\n/** The last day whose conversions have settled on a platform. */\nexport interface AdMatureThrough {\n platform: AdPerformancePlatform;\n date: string;\n lagDays: number;\n}\n\nexport interface AdConversionGoal {\n platform: AdPerformancePlatform;\n /** One ad account's own choice; absent for the platform's, which every account without one follows. */\n adAccountId?: string;\n actions: string[];\n countValue: boolean;\n updatedAt: number;\n}\n\nexport interface AdDataStatusAccount {\n adAccountId: string;\n name: string;\n currency: string;\n selected: boolean;\n /** The oldest day stored. */\n historyFrom: string | null;\n newestDate: string | null;\n backfillComplete: boolean;\n lastSuccessAt: number | null;\n error: string | null;\n /**\n * Ads whose numbers in the last 30 days came from more than one ad group or\n * campaign (Google keeps one ad id in every ad group it was copied into):\n * their days are added together under one ad, at its live placement.\n */\n adsInManyAdGroups: string[];\n}\n\nexport interface AdDataStatusPlatform {\n platform: AdPerformancePlatform;\n connected: boolean;\n running: boolean;\n lastSuccessAt: number | null;\n error: string | null;\n accounts: AdDataStatusAccount[];\n}\n\nexport interface AdDataStatus {\n platforms: AdDataStatusPlatform[];\n /** Some selected ad account is still loading its history. */\n historyLoading: boolean;\n}\n\nexport type AdAlertSeverity = \"critical\" | \"warning\" | \"info\";\n\n/** \"Not now\" holds until something changes; \"wrong\" until it turns critical. */\nexport interface AdAlertDismissal {\n kind: \"not_now\" | \"wrong\";\n reason: string | null;\n at: number;\n}\n\n/**\n * Why an alert is back in front of a person: a new reason, an edit on it, a\n * new target, it got clearly worse, or it was marked fixed and the problem\n * was still there once the fix had time to show.\n */\nexport type AdAlertBack = \"new_reason\" | \"edited\" | \"target\" | \"worse\" | \"fix_did_not_hold\";\n\n/** Marked fixed: Baker checks it until `checkUntil` — the fix's results in — before calling it fixed or back. */\nexport interface AdAlertHandled {\n at: number;\n note: string | null;\n /** The chat that fixed it; null when a person marked it fixed. */\n byChatId: string | null;\n checkUntil: number;\n}\n\nexport interface AdAlert {\n id: string;\n platform: AdPerformancePlatform;\n adAccountId: string;\n level: string;\n entityId: string;\n entityName: string;\n rule: string;\n severity: AdAlertSeverity;\n status: \"open\" | \"resolved\" | \"dismissed\";\n title: string;\n message: string;\n /** What the marketer should do about it. */\n action: string;\n currency: string;\n /** Money at stake, in `currency`, when the rule can say. */\n moneyAtStake: number | null;\n /** \"After you changed … on …\" when a recent change probably explains it. */\n annotation: string | null;\n /** Why it happened, in plain words, when the rule can tell. */\n cause: string | null;\n /** The reason it had before, when it came back for a different one. */\n previousCause: string | null;\n /** How many times it has opened, this time included. */\n timesOpened: number;\n /** The target it was judged against, for a budget or account-target alert. */\n target: AdJudgingTarget | null;\n /** The chat working on it; null when none is, or the one that was has ended. */\n claimedByChatId: string | null;\n /** How and why a person dismissed it, while it is dismissed. */\n dismissal: AdAlertDismissal | null;\n /** Why it is back in front of a person, until it is dismissed or fixed again. */\n back: AdAlertBack | null;\n /** Marked fixed and being checked; null otherwise. */\n handled: AdAlertHandled | null;\n firstDetectedAt: number;\n lastDetectedAt: number;\n}\n\nexport interface AdAlertCounts {\n critical: number;\n warning: number;\n info: number;\n}\n\n// --- Responses ---\n\nexport interface AdPlatformScore {\n platform: AdPerformancePlatform;\n currency: string;\n metrics: AdMetrics;\n ratios: AdRatios;\n activeCampaigns: number;\n matureThrough: string;\n /** Settled days of the window against as many days before them; null when none has settled. */\n comparison: { current: AdDayWindow; previous: AdDayWindow; previousMetrics: AdMetrics; deltas: AdDeltas } | null;\n}\n\nexport interface AdTrendPoint {\n bucket: string;\n groupKey: string;\n platform: AdPerformancePlatform;\n currency: string;\n metrics: AdMetrics;\n ratios: AdRatios;\n /** Every day of the bucket has settled on its platform. */\n mature: boolean;\n}\n\n/** A trend point, or with `--group-by none` one summing every platform (`all`), mature when each one is. */\nexport type AdTrendSeriesPoint = AdTrendPoint | (Omit<AdTrendPoint, \"platform\"> & { platform: \"all\" });\n\nexport interface AdPerformanceTrendData {\n window: AdReportWindow;\n granularity: AdTrendGranularity;\n groupBy: AdTrendGroup;\n /**\n * One per bucket, group, platform and currency. `groupKey`: the ad account or\n * campaign id, the campaign type, the segment, the platform, `__other`, or\n * `''` for `none`. `bucket` is the bucket's first day.\n */\n points: AdTrendSeriesPoint[];\n matureThrough: AdMatureThrough[];\n}\n\nexport interface AdPerformanceOverviewData {\n window: AdReportWindow;\n platforms: AdPlatformScore[];\n totalsByCurrency: Array<{ currency: string; metrics: AdMetrics; ratios: AdRatios }>;\n trend: AdTrendPoint[];\n matureThrough: AdMatureThrough[];\n goals: AdConversionGoal[];\n /** What one result is called here: the company's own name, else read from the goals of the accounts in view. */\n resultNoun: AdResultNoun;\n openAlerts: AdAlertCounts;\n topAlerts: AdAlert[];\n dataStatus: AdDataStatus;\n}\n\nexport interface AdEntityRow {\n platform: AdPerformancePlatform;\n adAccountId: string;\n level: string;\n entityId: string;\n campaignId: string;\n adGroupId: string;\n name: string;\n campaignName: string;\n adGroupName: string;\n status: string;\n platformStatus: string;\n deliveryStatus: string;\n objective: string;\n kind: string;\n currency: string;\n budgetDaily: number | null;\n budgetLifetime: number | null;\n bidStrategy: string;\n startTime: string | null;\n endTime: string | null;\n createdTime: string | null;\n creativeKey: string;\n creativeFormat: string;\n headline: string;\n body: string;\n callToAction: string;\n destinationUrl: string;\n urlTags: string;\n thumbnailUrl: string;\n attributes: Record<string, string>;\n metrics: AdMetrics;\n ratios: AdRatios;\n deliveryDays: number;\n firstDelivery: string | null;\n lastDelivery: string | null;\n /** It was running before the stored history starts: `firstDelivery` is not its launch. */\n beforeHistory: boolean;\n lifetimeSpend: number;\n lifetimeResults: number;\n /** Its share of the parent's spend and results in the window, and its cost per result against the parent's. */\n peer: { spendShare: number | null; resultShare: number | null; costPerResultIndex: number | null };\n /** Its campaign's type: Google's channel type (`SEARCH`, `PERFORMANCE_MAX`, …), Meta's buying type… */\n campaignKind: string;\n /** Its campaign's brand segment (`AdBrandSegment`); '' off Google. */\n segment: string;\n /** Its campaign's keywords buy more than one segment in earnest. */\n segmentMixed: boolean;\n /** A person chose this campaign's segment over Baker's reading; set on the campaign list's Google rows. */\n segmentChosen?: boolean;\n /**\n * When the read compared: the window's settled days (`current`) against as\n * many days before them (`previous`). An entity with spend before and none\n * in the window stopped.\n */\n comparison: { current: AdMetrics; previous: AdMetrics; previousRatios: AdRatios; deltas: AdDeltas } | null;\n /**\n * When it spent before and nothing in the window: the change that stopped it\n * (paused, ended, removed) from the change log, with who made it; null when\n * the log names none — then nobody is known to have stopped it.\n */\n stop: {\n changedAt: number;\n kind: string;\n newValue: string;\n actorKind: string;\n actor: string;\n chatTitle: string;\n } | null;\n}\n\n/**\n * Which searches a Google Search campaign buys: the company's own brand, a\n * competitor's, or neither. `other` is a campaign that buys no searches by\n * keyword (Performance Max, Shopping, Display, Video, Demand Gen);\n * `unsorted` one not decided yet.\n */\nexport type AdBrandSegment = (typeof AD_BRAND_SEGMENT_NAMES)[number];\n\nexport interface AdPerformanceEntitiesData {\n window: AdReportWindow;\n matureThrough: AdMatureThrough[];\n level: AdEntityLevel;\n rows: AdEntityRow[];\n /** Every row the filters match, whatever `limit` and `offset` returned: what spent, what stopped, and (with `includeIdle`) what did neither. */\n totalRows: number;\n /** Of `totalRows`, the ones that spent in the period: what \"N campaigns spent\" counts. */\n spentRows: number;\n /** Of `totalRows`, the ones that spent in the period before and nothing in this one (with `compare`). */\n stoppedRows: number;\n}\n\nexport interface AdDailyRow {\n date: string;\n currency: string;\n metrics: AdMetrics;\n ratios: AdRatios;\n mature: boolean;\n}\n\nexport interface AdChangeRow {\n changedAt: number;\n platform: AdPerformancePlatform;\n adAccountId: string;\n level: string;\n entityId: string;\n entityName: string;\n campaignId: string;\n campaignName: string;\n adGroupId: string;\n source: string;\n kind: string;\n field: string;\n oldValue: string;\n newValue: string;\n /** The ad account's own currency, which amounts in `oldValue` / `newValue` are in; \"\" when unknown. */\n valueCurrency: string;\n /** When the report shows another currency: that currency and the rate from `valueCurrency` into it (`fx.ts` `changeAmountsShown`). */\n shownIn?: { currency: string; rate: number };\n actor: string;\n actorKind: string;\n /** The Baker chat that published it; \"\" when it was made outside Baker. */\n chatId: string;\n /** That chat's title, when Baker still has the chat; \"\" otherwise. */\n chatTitle: string;\n /**\n * For a change made in Baker: whether the ad platform shows it too (`seen`),\n * or still does not a day later (`not_seen`). Null when made outside Baker,\n * too recent, or a change the platform side cannot vouch for (a keyword, an audience).\n */\n platformCheck: \"seen\" | \"not_seen\" | null;\n}\n\n/** The read before a change: is there enough to judge it, and how far may it go. */\nexport interface AdEntityVerdict {\n /** False for an entity that cannot deliver now (archived, removed, ended, paused and idle 14 days): hide the block, show `summary`. */\n applies: boolean;\n /** One line when `applies` is false (\"Stopped on 22 Jan 2026: no decision to make.\"); null otherwise. */\n summary: string | null;\n /** Its last delivery day, `YYYY-MM-DD`, when it stopped. */\n stoppedOn: string | null;\n /** The last settled day the data verdict reads, `YYYY-MM-DD`. */\n maturedThrough: string;\n enoughData: boolean;\n enoughDataReason: string;\n maturedResults: number;\n maturedSpend: number;\n /** Days since the last change a person or Baker made to it or a parent; null when none in the window. */\n daysSinceChange: number | null;\n lastChangeKind: string | null;\n learning: boolean;\n learningReason: string;\n /** The newest edit that restarted learning and whose settled week is not in yet. */\n lastReset?: { day: string; kind: string } | null;\n /** The first day it is fair to judge or change it again, `YYYY-MM-DD`; null when that is now. */\n waitUntil?: string | null;\n /** The largest budget step that does not reset the platform's learning, and when it may be taken. */\n safeBudgetStep: {\n maxIncreasePct: number;\n currentDailyBudget: number | null;\n suggestedDailyBudget: number | null;\n waitDays: number;\n reason: string;\n };\n}\n\nexport interface AdPerformanceEntityData {\n window: AdReportWindow;\n matureThrough: string;\n entity: AdEntityRow | null;\n daily: AdDailyRow[];\n changes: AdChangeRow[];\n children: { level: AdEntityLevel; rows: AdEntityRow[]; totalRows: number } | null;\n openAlerts: AdAlert[];\n verdict: AdEntityVerdict | null;\n /** `window` is the entity's first to last day of delivery rather than the period asked. */\n wholeRun: boolean;\n}\n\nexport interface AdPerformanceChangesData {\n window: AdReportWindow;\n changes: AdChangeRow[];\n /** Every change the filters match, whatever `limit` and `offset` returned. */\n totalRows: number;\n}\n\n/** `stopped`: the change removed the entity, so there is no after period to judge. */\nexport type AdImpactVerdict = \"too_early\" | \"better\" | \"worse\" | \"unclear\" | \"stopped\";\n\nexport interface AdImpactSide {\n spend: number;\n impressions: number;\n clicks: number;\n linkClicks: number;\n results: number;\n resultValue: number;\n}\n\nexport interface AdChangeImpactRow extends Omit<AdChangeRow, \"campaignName\"> {\n currency: string;\n before: AdImpactSide;\n after: AdImpactSide;\n controlBefore: AdImpactSide;\n controlAfter: AdImpactSide;\n beforeDays: number;\n afterDays: number;\n confounded: boolean;\n /**\n * How many of one publish's edits to this setting the line stands for (sixty\n * negative keywords added to one campaign are one line); 1 for any other change.\n */\n edits: number;\n /** What each of those edits set, oldest first; capped, while `edits` counts them all. */\n editValues: string[];\n verdict: AdImpactVerdict;\n /** What was compared: results per spend, results, or link clicks per spend. */\n basis: \"results_per_spend\" | \"results\" | \"link_clicks_per_spend\" | null;\n /** The change's effect beyond what the rest of the ad account did, relative (`0.2` = +20 %). */\n effect: number | null;\n reason: string;\n}\n\nexport interface AdPerformanceImpactData {\n window: AdReportWindow;\n impactDays: number;\n changes: AdChangeImpactRow[];\n /** Every change the filters match, whatever `limit` and `offset` returned. */\n totalRows: number;\n}\n\nexport interface AdCreativeRow {\n /** What its card groups by: the picture or video, or an ad re-run with the same name and copy. */\n groupKey: string;\n /**\n * The top-spending ad's picture or video (`creative_key`): what the library\n * and Baker's own creatives link by. The group key unless re-runs grouped by copy.\n */\n mediaKey: string;\n platform: string;\n platforms: string[];\n adAccountId: string;\n topAdId: string;\n currency: string;\n name: string;\n headline: string;\n body: string;\n thumbnailUrl: string;\n imageUrl: string;\n creativeFormat: string;\n destinationUrl: string;\n ads: number;\n adGroups: number;\n activeAds: number;\n /** The platform's status word: `active` when any of its ads runs, else its top-spending ad's (`paused`, `removed`, …). */\n status: string;\n metrics: AdMetrics;\n ratios: AdRatios;\n expectedResults: number;\n expectedLinkClicks: number;\n peerBasis: \"results\" | \"link_clicks\" | null;\n peerIndex: number | null;\n peerStanding: \"above_peers\" | \"like_peers\" | \"below_peers\" | \"too_little_data\";\n firstDelivery: string | null;\n lastDelivery: string | null;\n /** The creative's family in the winning-ads library and what it read in it; null until checked. */\n library: AdCreativeLibraryLink | null;\n /** The company's own creative (and version) this picture or video is; null when none is. */\n madeInBaker: AdMadeInBaker | null;\n}\n\n/**\n * The creative made in Baker that an ad runs: published from Baker, or read\n * from the pictures (`convex/creatives/adMatch.ts`). `likely` when the\n * pictures are close but not the same — an edit, or another creative as alike.\n */\nexport interface AdMadeInBaker {\n slug: string;\n title: string;\n /** \"Version N\" on the creative's page; null for its library picture. */\n versionNumber: number | null;\n confidence: \"same\" | \"likely\";\n}\n\nexport interface AdPerformanceCreativesData {\n window: AdReportWindow;\n matureThrough: AdMatureThrough[];\n groupBy: \"creative\" | \"ad\";\n creatives: AdCreativeRow[];\n}\n\nexport interface AdBreakdownRow {\n platform: string;\n value: string;\n currency: string;\n spend: number;\n impressions: number;\n clicks: number;\n linkClicks: number;\n conversions: number;\n conversionValue: number;\n results: number;\n resultValue: number;\n spendShare: number | null;\n resultShare: number | null;\n costPerResult: number | null;\n ctr: number | null;\n}\n\nexport interface AdPerformanceBreakdownData {\n window: AdReportWindow;\n dimension: (typeof AD_BREAKDOWN_DIMENSIONS)[number];\n rows: AdBreakdownRow[];\n}\n\nexport interface AdSearchTermRow {\n searchTerm: string;\n matchType: string;\n keywordId: string;\n keywordText: string;\n status: string;\n campaignId: string;\n campaignName: string;\n adGroupId: string;\n adGroupName: string;\n currency: string;\n spend: number;\n impressions: number;\n clicks: number;\n conversions: number;\n conversionValue: number;\n costPerConversion: number | null;\n ctr: number | null;\n weeks: number;\n /** What the term was read as: `brand`, `competitor`, `non_brand`, or `unsorted` while not read yet. */\n termSegment: string;\n /** Read in the middle band: worth a person's look. */\n termUnsure: boolean;\n /** A person chose its segment. */\n termChosen: boolean;\n /** The buying campaign's segment (`AdBrandSegment`). */\n campaignSegment: string;\n}\n\nexport interface AdPerformanceSearchTermsData {\n window: AdReportWindow;\n rows: AdSearchTermRow[];\n totalRows: number;\n}\n\nexport interface AdPacingRow {\n platform: string;\n adAccountId: string;\n currency: string;\n mtdSpend: number;\n last7Spend: number;\n activeDailyBudget: number;\n lifetimeBudgetRemaining: number;\n activeCampaigns: number;\n dailyRunRate: number;\n projectedSpend: number;\n daysRemaining: number;\n}\n\nexport interface AdPerformancePacingData {\n month: string;\n asOf: string;\n rows: AdPacingRow[];\n}\n\nexport interface AdFunnelRow {\n platform: string;\n /** `\"\"` on the row for that platform's paid visits that carried no id for the level. */\n entityId: string;\n untagged: boolean;\n landingId: string;\n path: string;\n name: string;\n currency: string;\n spend: number;\n impressions: number;\n linkClicks: number;\n results: number;\n sessions: number;\n engagedSessions: number;\n convertingSessions: number;\n siteConversions: number;\n identifiedPeople: number;\n /** Visits per link click: below ~0.6 the clicks are not arriving, or not arriving tagged. */\n clickToSession: number | null;\n siteConversionRate: number | null;\n costPerSiteConversion: number | null;\n}\n\nexport interface AdPerformanceFunnelData {\n /** The days the answer covers: visits are kept 400 days, so a longer window is clipped (`windowClipped`). */\n window: AdReportWindow;\n windowClipped: boolean;\n level: (typeof AD_FUNNEL_LEVELS)[number];\n byLanding: boolean;\n rows: AdFunnelRow[];\n}\n\nexport interface AdTrackingRow {\n platform: string;\n paidSessions: number;\n withClickId: number;\n withCampaignId: number;\n withAdId: number;\n resolvable: number;\n /** Shares of paid visits, 0–1; null without paid visits. */\n clickIdShare: number | null;\n campaignIdShare: number | null;\n adIdShare: number | null;\n resolvableShare: number | null;\n activeAds: number;\n activeAdsOnBakerHosts: number;\n activeAdsWithoutParams: number;\n spend7dWithoutParams: Array<{ currency: string; spend: number }>;\n}\n\nexport interface AdPerformanceTrackingData {\n /** The days the answer covers: visits are kept 400 days, so a longer window is clipped (`windowClipped`). */\n window: AdReportWindow;\n windowClipped: boolean;\n rows: AdTrackingRow[];\n}\n\nexport interface AdLandingTrafficRow {\n landingId: string;\n name: string;\n path: string;\n activeAds: number;\n campaigns: number;\n platforms: string[];\n spend: Array<{ currency: string; spend: number }>;\n sessionsPaid: number;\n siteConversionsPaid: number;\n}\n\nexport interface AdPerformanceLandingsData {\n /** The days the answer covers: visits are kept 400 days, so a longer window is clipped (`windowClipped`). */\n window: AdReportWindow;\n windowClipped: boolean;\n rows: AdLandingTrafficRow[];\n}\n\nexport interface AdConversionActionRow {\n platform: AdPerformancePlatform;\n /** The platform's key, as goals store it (LinkedIn: `conversion:<rule id>`, `one_click_leads`). */\n action: string;\n /** What to show a person: the platform's name for it, else the key. */\n label: string;\n /** The ad accounts' currency `value` is in: one row per currency, never added across. */\n currency: string;\n conversions: number;\n value: number;\n /** Counted as a result today. */\n inGoal: boolean;\n}\n\n/** A readable name for an action key that is not one (LinkedIn's conversion rule ids). */\nexport interface AdConversionActionLabel {\n platform: AdPerformancePlatform;\n action: string;\n label: string;\n}\n\nexport interface AdPerformanceGoalsData {\n goals: AdConversionGoal[];\n /** Every name known for a key that is not readable, goal actions with no conversions in the window included. */\n labels: AdConversionActionLabel[];\n actions: AdConversionActionRow[];\n window: AdReportWindow;\n}\n\n// --- Getting better or worse ---\n\nexport type AdJudgedMetric =\n | \"result_value_per_spend\"\n | \"cost_per_result\"\n | \"cost_per_visit\"\n | \"cost_per_link_click\"\n | \"cost_per_video_view\"\n | \"cost_per_engagement\"\n | \"cpm\";\n\n/** The metric the entity is judged on, chosen by what it is for, and its move. */\nexport interface AdJudged {\n metric: AdJudgedMetric;\n /** Why this metric, and the fallback when there was too little to judge the first choice. */\n why: string;\n recent: number | null;\n baseline: number | null;\n /** `0.2` = +20 %. For return on ad spend up is good; for every cost down is good (`higherIsBetter`). */\n changePct: number | null;\n fallbackFrom: AdJudgedMetric | null;\n higherIsBetter: boolean;\n}\n\n/** One explanation: `not_real` (measurement), `explains` (the cause), `context` (expected or shared), `contradicts`. */\nexport interface AdFinding {\n lens: string;\n effect: \"not_real\" | \"explains\" | \"context\" | \"contradicts\";\n weight: number;\n sentence: string;\n /** What to check next, in plain words. */\n check: string;\n /** The `baker` command that runs the check, when there is one. */\n command?: string;\n}\n\n/** A part of the cost chain and its share of the judged metric's move toward worse. */\nexport interface AdDriver {\n part: \"auction_cost\" | \"click_rate\" | \"conversion_rate\" | \"visit_rate\" | \"value_per_result\";\n change: number;\n share: number;\n}\n\nexport interface AdImpressionShareSide {\n won: number;\n lostBudget: number;\n lostRank: number;\n}\n\nexport interface AdDiagnosis {\n status: AdProgressStatus;\n confidence: \"strong\" | \"moderate\" | \"weak\" | null;\n judged: AdJudged | null;\n drivers: AdDriver[];\n impressionShare: { recent: AdImpressionShareSide; baseline: AdImpressionShareSide } | null;\n /** When spend per day rose 30 %+: the average cost against what each extra event of the judged metric cost (a result, click, visit, video view, engagement or 1,000 impressions). */\n marginal: { spendChangePct: number; averageCost: number | null; marginalCost: number | null } | null;\n findings: AdFinding[];\n /** Worsening only: money spent above what the baseline rate needed. */\n atStake: number | null;\n headline: string;\n next: string;\n windows: { recent: AdDayWindow; baseline: AdDayWindow };\n recentSpend: number;\n baselineSpend: number;\n}\n\n/** One settled week of the judged metric (cost per click for a visit metric). */\nexport interface AdProgressPoint {\n weekEnd: string;\n value: number | null;\n spend: number;\n impressions: number;\n linkClicks: number;\n results: number;\n}\n\nexport interface AdProgressRow {\n platform: AdPerformancePlatform;\n adAccountId: string;\n level: string;\n entityId: string;\n name: string;\n campaignId: string;\n adGroupId: string;\n currency: string;\n /** The day its windows end on. */\n asOf: string;\n status: AdProgressStatus;\n confidence: \"strong\" | \"moderate\" | \"weak\" | null;\n judged: AdJudged | null;\n spend: number;\n atStake: number | null;\n headline: string;\n next: string;\n topFinding: AdFinding | null;\n sparkline: AdProgressPoint[];\n}\n\nexport interface AdPerformanceProgressData {\n window: AdReportWindow;\n level: (typeof AD_FUNNEL_LEVELS)[number];\n /** Per platform, the last settled day the windows end on. */\n asOf: AdMatureThrough[];\n counts: Record<AdProgressStatus, number>;\n rows: AdProgressRow[];\n}\n\nexport interface AdMilestone {\n at: number;\n day: string;\n kind: string;\n level: string;\n entityId: string;\n label: string;\n}\n\nexport interface AdPerformanceDiagnosisData {\n window: AdReportWindow;\n asOf: string;\n entity: {\n platform: AdPerformancePlatform;\n adAccountId: string;\n level: string;\n entityId: string;\n name: string;\n campaignId: string;\n adGroupId: string;\n currency: string;\n status: string;\n objective: string;\n optimizationGoal: string;\n } | null;\n diagnosis: AdDiagnosis | null;\n trajectory: AdProgressPoint[];\n milestones: AdMilestone[];\n}\n\nexport interface AdPulseMetric {\n value: number | null;\n mean: number | null;\n spread: number | null;\n changePct: number | null;\n /** Outside the usual range of the 7 settled days before. */\n watch: boolean;\n}\n\nexport interface AdPulseRow {\n platform: AdPerformancePlatform;\n adAccountId: string;\n currency: string;\n day: string;\n spend: AdPulseMetric;\n results: AdPulseMetric;\n costPerResult: AdPulseMetric;\n linkCtr: AdPulseMetric;\n cpm: AdPulseMetric;\n frequency: AdPulseMetric;\n}\n\nexport interface AdPerformancePulseData {\n matureThrough: AdMatureThrough[];\n rows: AdPulseRow[];\n}\n\ntype Envelope<T> = { ok: true; data: T };\nexport type AdPerformanceOverviewResponse = Envelope<AdPerformanceOverviewData>;\nexport type AdPerformanceTrendResponse = Envelope<AdPerformanceTrendData>;\nexport type AdPerformanceEntitiesResponse = Envelope<AdPerformanceEntitiesData>;\nexport type AdPerformanceEntityResponse = Envelope<AdPerformanceEntityData>;\nexport type AdPerformanceChangesResponse = Envelope<AdPerformanceChangesData>;\nexport type AdPerformanceImpactResponse = Envelope<AdPerformanceImpactData>;\nexport type AdPerformanceCreativesResponse = Envelope<AdPerformanceCreativesData>;\nexport type AdPerformanceBreakdownResponse = Envelope<AdPerformanceBreakdownData>;\nexport type AdPerformanceSearchTermsResponse = Envelope<AdPerformanceSearchTermsData>;\nexport type AdPerformancePacingResponse = Envelope<AdPerformancePacingData>;\nexport type AdPerformanceFunnelResponse = Envelope<AdPerformanceFunnelData>;\nexport type AdPerformanceTrackingResponse = Envelope<AdPerformanceTrackingData>;\nexport type AdPerformanceLandingsResponse = Envelope<AdPerformanceLandingsData>;\nexport type AdPerformanceStatusResponse = Envelope<AdDataStatus>;\nexport type AdPerformanceGoalsResponse = Envelope<AdPerformanceGoalsData>;\nexport type AdPerformanceProgressResponse = Envelope<AdPerformanceProgressData>;\nexport type AdPerformanceDiagnosisResponse = Envelope<AdPerformanceDiagnosisData>;\nexport type AdPerformancePulseResponse = Envelope<AdPerformancePulseData>;\n\n/**\n * The refusal when the company has no ad platform connected: the backend\n * throws it as a CONFLICT and the CLI turns it into an `error.fix`.\n */\nexport const AD_PERFORMANCE_NOT_CONNECTED_MESSAGE =\n \"No ad platform is connected with an ad account selected, so there are no ad results to read yet.\";\n","/**\n * What a report shows amounts in (`convex/adPerformance/fx.ts`): an ISO 4217\n * code, any case, or `native` for each ad account's own currency. Its own\n * module so every report family's request schema can take it.\n */\n\nimport { z } from \"zod\";\n\nexport const adReportCurrencySchema = z\n .string()\n .regex(/^([A-Za-z]{3}|native)$/, \"use a currency code like EUR, or native\")\n .transform((value) => (value === \"native\" ? value : value.toUpperCase()));\n\n/**\n * How the reporting currency was decided: saved by a person (`saved`), the\n * accounts' only currency, EUR with no account (`default`), or the currency\n * the company spent most in over the last 30 days (`most_spend`).\n */\nexport type AdReportingCurrencySource = \"saved\" | \"only_account_currency\" | \"default\" | \"most_spend\";\n\n/** `baker ads performance currency`: the company's reporting currency, how it was decided, and what it can be. */\nexport const adReportingCurrencyRequestSchema = z.object({\n /** Show what this chat staged on top. */\n chatId: z.string().min(1).optional(),\n});\nexport type AdReportingCurrencyRequest = z.input<typeof adReportingCurrencyRequestSchema>;\n\nexport interface AdReportingCurrencyData {\n /** What every Ads screen and report shows amounts in when none is asked. */\n currency: string;\n source: AdReportingCurrencySource;\n /** The one a person saved (\"Use as default\"); null when none is. */\n saved: string | null;\n /** The currencies of the company's selected ad accounts. */\n accountCurrencies: string[];\n /** Every currency an amount can be shown in: the ECB's published rates. */\n convertible: string[];\n /** The reporting currency this chat staged, in words, until it is published; null when it staged none. */\n staged: { before: string; after: string; key: string } | null;\n}\nexport type AdReportingCurrencyResponse = { ok: true; data: AdReportingCurrencyData };\n\n/**\n * `baker ads performance currency set`: stage the company's reporting\n * currency (an ISO code), or `null` to go back to the one it spends most in.\n * Applied when the chat is published.\n */\nexport const adReportingCurrencyStageRequestSchema = z.object({\n chatId: z.string().min(1),\n currency: z\n .string()\n .regex(/^[A-Za-z]{3}$/, \"use a currency code like EUR\")\n .transform((value) => value.toUpperCase())\n .nullable(),\n});\nexport type AdReportingCurrencyStageRequest = z.input<typeof adReportingCurrencyStageRequestSchema>;\n","/**\n * Wire contract for \"what needs attention\": one ranked feed of the few things\n * a marketer should look at in their ads right now, built from Baker's own\n * store (`convex/adPerformance/attentionReport.ts`) — the open alerts, the\n * campaigns judged against each ad account's target, and the ads not earning\n * their spend. Nothing here calls or changes an ad platform.\n *\n * Three tiers, ranked tier first then money at stake:\n * - `fix_now`: money is being wasted, or delivery or tracking broke.\n * - `worth_a_look`: off target, or getting worse.\n * - `opportunity`: a campaign beating its target that its budget holds back.\n */\n\nimport { z } from \"zod\";\nimport { adReportCurrencySchema } from \"./currency\";\nimport type { AdJudgingTarget } from \"./targets\";\nimport type { AdAlertBack, AdAlertDismissal, AdAlertHandled } from \"./wire\";\n\n/** Kept apart from `./index` on purpose: that module re-exports this one. */\nconst ATTENTION_PLATFORMS = [\"meta\", \"google\", \"linkedin\", \"x\", \"chatgpt\"] as const;\ntype AttentionPlatform = (typeof ATTENTION_PLATFORMS)[number];\n\nexport const AD_ATTENTION_TIERS = [\"fix_now\", \"worth_a_look\", \"opportunity\"] as const;\nexport type AdAttentionTier = (typeof AD_ATTENTION_TIERS)[number];\n\n/**\n * Where an item came from: a stored alert, an account against its target, a\n * budget judgement, ads not earning their spend, an account well worse\n * than its own 4 settled weeks before, or an account that spends daily and\n * has spent nothing for at least 2 settled days.\n */\nexport type AdAttentionSource = \"alert\" | \"target\" | \"budget\" | \"creatives\" | \"trend\" | \"stopped\" | \"brand\";\n\n/** The section of Measure → Ads an item opens when it is not about one campaign, ad set or ad. */\nexport type AdAttentionSection = \"campaigns\" | \"creatives\" | \"setup\" | \"goals\" | \"status\" | \"brand\";\n\n/** The one thing to do: open a campaign, ad set or ad, or a section. */\nexport type AdAttentionAction =\n | { label: string; open: \"entity\"; level: string; entityId: string }\n | { label: string; open: \"section\"; section: AdAttentionSection };\n\nexport interface AdAttentionItem {\n /** Stable across reads and syncs: the rule and what it is about. */\n key: string;\n tier: AdAttentionTier;\n source: AdAttentionSource;\n platform: AttentionPlatform;\n adAccountId: string;\n /** The ad account's name, or its id when the name is not known. */\n accountName: string;\n /** What the item is about: `account`, `campaign`, `ad_group`, `ad`. */\n level: string;\n entityId: string;\n entityName: string;\n /** One plain sentence. */\n title: string;\n /** Why, in numbers; null when the title says it all. */\n detail: string | null;\n /** The target it was judged against and where that is set, for an item about a target; null otherwise. */\n target: AdJudgingTarget | null;\n action: AdAttentionAction;\n /** Money wasted or to be gained, in `currency`; null when it cannot be said. */\n moneyAtStake: number | null;\n /** The report currency, or the account's own when no rate converts it. */\n currency: string;\n /** The stored alert behind it: what a dismissal, a claim or a trigger names. */\n alertId: string;\n /** The rule that found it (`alerts.ts` `ALERT_RULES`). */\n rule: string;\n /** Why it happened, in plain words, when Baker can tell. */\n cause: string | null;\n /** The reason it had before, when it came back for a different one. */\n previousCause: string | null;\n /** How many times it has opened, this time included. */\n timesOpened: number;\n /** Other problems on the same campaign, ad set, ad or account, behind this one. */\n more: number;\n /** The chat working on it (\"An agent is working on this\"); null when none is. */\n claimedByChatId: string | null;\n /** How and why a person dismissed it; only on `dismissedItems`. */\n dismissal: AdAlertDismissal | null;\n /** Why it is back in front of a person: after a dismissal, or a fix that did not hold. */\n back: AdAlertBack | null;\n /** Marked fixed and being checked (\"Fixed, checking it worked\"); ranked after every to-do. */\n handled: AdAlertHandled | null;\n}\n\nconst HANDLE_ALERT_PROMPT_RE = /^\\s*Handle alert @\\[[^\\]]*\\]\\(adAlert:([^)?\\s]+)\\)/;\n\n/**\n * The chat \"Handle with agent\" opens: the alert as a mention the chat shows\n * as a chip, and what to do first. The send claims the alert for the chat\n * (`handledAlertIdIn`), as \"Solve with agent\" claims a Task.\n */\nexport function handleAlertPrompt(item: { alertId: string; title: string }): string {\n const title = item.title.replace(/\\[/g, \"(\").replace(/\\]/g, \")\");\n return `Handle alert @[${title}](adAlert:${item.alertId}): read what is behind it, find the cause, stage the fix for me to review, and mark the alert fixed. `;\n}\n\n/** The alert a chat's opening prompt asks it to handle, as the raw id its mention carries; null for any other prompt. */\nexport function handledAlertIdIn(prompt: string): string | null {\n return HANDLE_ALERT_PROMPT_RE.exec(prompt)?.[1] ?? null;\n}\n\nexport interface AdPerformanceAttentionData {\n /** What the money is shown in; '' when each account keeps its own. */\n currency: string;\n /** The settled days the target and creative judgements read. */\n window: { from: string; to: string };\n counts: Record<AdAttentionTier, number>;\n /** Ranked: tier, then money at stake. */\n items: AdAttentionItem[];\n /** Items hidden because a person dismissed them. */\n dismissed: number;\n /** Those items, when asked for (`includeDismissed`), most recently dismissed first. */\n dismissedItems: AdAttentionItem[];\n /** No target is set anywhere: the target and budget judgements are off. */\n hasTarget: boolean;\n}\n\nconst idList = z\n .array(\n z\n .string()\n .min(1)\n .regex(/^[^,]+$/, \"ids cannot contain commas\"),\n )\n .max(200);\n\nexport const adPerformanceAttentionRequestSchema = z.object({\n platforms: z.array(z.enum(ATTENTION_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n /** ISO code to show money in, or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n tiers: z.array(z.enum(AD_ATTENTION_TIERS)).optional(),\n limit: z.number().int().min(1).max(100).default(20),\n /** Also return the dismissed items, with how and why each was dismissed. */\n includeDismissed: z.boolean().optional(),\n});\nexport type AdPerformanceAttentionRequest = z.input<typeof adPerformanceAttentionRequestSchema>;\n\nexport type AdPerformanceAttentionResponse = { ok: true; data: AdPerformanceAttentionData };\n\n/** `baker ads performance attention claim | release <id>`: this chat starts or stops working on an alert, at once. */\nexport const adAlertClaimRequestSchema = z.object({\n chatId: z.string().min(1),\n alertId: z.string().min(1).max(64),\n});\nexport type AdAlertClaimRequest = z.input<typeof adAlertClaimRequestSchema>;\n\n/**\n * An alert's verdict from the agent, staged on its chat and applied at\n * Publish: fixed (what it did, in a note), dismissed — \"not now\", or\n * \"wrong\" with the reason it is not a real problem — or, for one a person\n * dismissed, brought back to the list (`restore`).\n */\nexport const AD_ALERT_VERDICTS = [\"fixed\", \"not_now\", \"wrong\", \"restore\"] as const;\nexport type AdAlertVerdict = (typeof AD_ALERT_VERDICTS)[number];\n\nexport const adAlertVerdictRequestSchema = z\n .object({\n chatId: z.string().min(1),\n alertId: z.string().min(1).max(64),\n verdict: z.enum(AD_ALERT_VERDICTS),\n note: z.string().trim().max(500).optional(),\n })\n .refine((body) => body.verdict !== \"wrong\" || (body.note ?? \"\") !== \"\", {\n message: \"Say why it is wrong with --reason: that is what Baker learns from.\",\n path: [\"reason\"],\n });\nexport type AdAlertVerdictRequest = z.input<typeof adAlertVerdictRequestSchema>;\n\nexport interface AdAlertClaimData {\n id: string;\n /** `not_claimed`: a release of an alert no chat was working on, which changed nothing. */\n state: \"claimed\" | \"released\" | \"not_claimed\";\n /** What happened, when it is not what was asked. */\n message?: string;\n}\n","/**\n * One ad change in a marketer's words — the same in the dashboard and in\n * `baker ads performance changes`. Platforms log changes in their own field\n * names (`maximize_conversions.target_cpa_micros`, `update_ad_set_target_spec`)\n * and raw values (JSON targeting, whole ad copy); this says what moved, with\n * amounts as money, and keeps the long text aside in `full`.\n */\n\nexport interface AdChangeFacts {\n platform?: string;\n /** `baker` | `platform` | `observed`: only Baker's own targeting rows carry a summary to read as is. */\n source?: string;\n kind: string;\n field: string;\n oldValue: string;\n newValue: string;\n /** The ad account's own currency, which change amounts are in; \"\" when unknown. */\n valueCurrency?: string;\n /** The report's currency and the rate into it, when the screen shows amounts converted (`AdChangeRow.shownIn`). */\n shownIn?: { currency: string; rate: number };\n}\n\nexport interface AdChangeWordsOptions {\n /**\n * How an amount names its currency: `code` once at the end (\"980 → 1,150 MXN\",\n * the CLI's, which the agent reads), or `symbol` on each side (\"MX$980 →\n * MX$1,150\", the dashboard's, like every other amount on screen).\n */\n money?: \"code\" | \"symbol\";\n}\n\nexport interface AdChangeWords {\n /** One short line: what moved, from what to what. */\n summary: string;\n /** The long text behind the summary (targeting, ad copy), for a hover or a disclosure; null when the summary says it all. */\n full: string | null;\n /**\n * With `money: \"symbol\"` and the report converting: the amounts as the ad\n * account logged them (\"MX$450 → MX$650 in the account's currency\"), for a\n * hover. Null otherwise.\n */\n original: string | null;\n}\n\ntype LineWords = Omit<AdChangeWords, \"original\">;\n\ntype ValueShape = \"money\" | \"multiple\" | \"state\" | \"text\" | \"none\";\n\ninterface FieldWords {\n label: string;\n shape: ValueShape;\n}\n\n/** Fields named by what they are to a marketer, keyed by the field with platform prefixes taken off. */\nconst FIELD_WORDS: Array<[RegExp, FieldWords]> = [\n // `budget_daily`, `budget_lifetime`, `cpc_bid` and `target_cpc` are Baker's own names (`diff.ts`, `publishedChanges.ts`).\n [/^(campaign_budget\\.)?amount_micros$|^daily_budget$|^budget_daily$/, { label: \"Daily budget\", shape: \"money\" }],\n [/total_amount_micros$|^lifetime_budget$|^budget_lifetime$/, { label: \"Total budget\", shape: \"money\" }],\n [/^budget$/, { label: \"Budget\", shape: \"money\" }],\n [/^spend_cap$|spend_limit/, { label: \"Spending limit\", shape: \"money\" }],\n [/budget_scheduling_state$/, { label: \"Budget scheduling\", shape: \"state\" }],\n [/target_cpa(_micros)?$|^cost_cap$/, { label: \"Target cost per result\", shape: \"money\" }],\n [/target_roas$/, { label: \"Target return on ad spend\", shape: \"multiple\" }],\n [/^cpc_bid(_micros)?$|^bid_amount$|^bid$/, { label: \"Max cost per click\", shape: \"money\" }],\n [/^target_cpc(_micros)?$/, { label: \"Target cost per click\", shape: \"money\" }],\n [/^cpm_bid_micros$/, { label: \"Max cost per 1,000 views\", shape: \"money\" }],\n [/^cpv_bid_micros$/, { label: \"Max cost per video view\", shape: \"money\" }],\n [/^bid_modifier$/, { label: \"Bid adjustments changed\", shape: \"none\" }],\n [\n /bid_strategy|bidding_strategy|^manual_cp|^maximize_conversion|^target_spend/,\n { label: \"Bid strategy\", shape: \"state\" },\n ],\n [/target_impression_share/, { label: \"Target impression share\", shape: \"none\" }],\n [/^(status|run_status)$/, { label: \"Status\", shape: \"state\" }],\n [/^name$/, { label: \"Name\", shape: \"text\" }],\n [/^(start_date|start_date_time|start_time)$/, { label: \"Start date\", shape: \"text\" }],\n [/^(end_date|end_date_time|end_time)$/, { label: \"End date\", shape: \"text\" }],\n [/run_dates|schedule/, { label: \"Schedule changed\", shape: \"none\" }],\n [/_criterion$/, { label: \"Targeting changed\", shape: \"none\" }],\n [/target_spec$|targeting/, { label: \"Targeting changed\", shape: \"none\" }],\n [/geo_target|network_settings/, { label: \"Where ads show changed\", shape: \"none\" }],\n [/language_code$|^languages?$/, { label: \"Language\", shape: \"text\" }],\n [/_asset$/, { label: \"Assets changed\", shape: \"none\" }],\n [/^final_urls$|^final_mobile_urls$/, { label: \"Landing page link changed\", shape: \"none\" }],\n [\n /^(tracking_url_template|final_url_suffix|url_custom_parameters|url_tags)$/,\n { label: \"Tracking settings changed\", shape: \"none\" },\n ],\n [/^ad(\\..+)?$|^creative$/, { label: \"Ad edited\", shape: \"none\" }],\n [/optimization_goal$/, { label: \"Optimizing for\", shape: \"state\" }],\n [/^objective$/, { label: \"Objective\", shape: \"state\" }],\n [/billing_charge$/, { label: \"Billing charge\", shape: \"money\" }],\n [/^first_delivery_event$/, { label: \"Started running\", shape: \"none\" }],\n // Google's brand guidelines are a campaign's main and accent colour and its font.\n [/^brand_guidelines/, { label: \"Brand colors and font changed\", shape: \"none\" }],\n // Google's text guidelines: words and claims its auto-written ad text must avoid.\n [/^text_guidelines/, { label: \"Rules for auto-written text changed\", shape: \"none\" }],\n [/^(ai_max_setting|asset_automation_settings)/, { label: \"Automated assets changed\", shape: \"none\" }],\n [/^shopping_setting/, { label: \"Shopping settings changed\", shape: \"none\" }],\n [/^frequency_caps?$/, { label: \"Frequency cap changed\", shape: \"none\" }],\n];\n\nconst KIND_WORDS: Record<string, string> = {\n created: \"Created\",\n status: \"Status\",\n budget: \"Budget\",\n bid: \"Bidding\",\n schedule: \"Schedule\",\n name: \"Name\",\n creative: \"Ad edited\",\n targeting: \"Targeting changed\",\n goal: \"Goal\",\n removed: \"Removed\",\n other: \"Changed\",\n};\n\n/**\n * A field as the vocabulary keys it: Google's dotted path in snake case, and\n * Meta's activity event without its `update_<level>_` prefix.\n */\nfunction bareField(field: string): string {\n return field\n .trim()\n .replace(/^(update|create)_(ad_account|campaign_group|campaign|ad_set|adset|ad)_/, \"\")\n .replace(/^ad_account_/, \"\")\n .replace(/^(maximize_conversions|maximize_conversion_value|target_cpa|target_roas)\\./, \"\")\n .replace(/^campaign_budget\\./, \"\");\n}\n\nfunction wordsFor(field: string): FieldWords | null {\n const bare = bareField(field);\n return FIELD_WORDS.find(([pattern]) => pattern.test(bare) || pattern.test(field))?.[1] ?? null;\n}\n\n/** `brand_guidelines.accent_color` → \"Brand guidelines accent color\"; `_micros` dropped. */\nfunction humanize(value: string): string {\n const spaced = value\n .replace(/_micros\\b/g, \"\")\n .replace(/[_.]+/g, \" \")\n .trim()\n .toLowerCase();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\n/**\n * Delivery statuses as a marketer reads them. Meta writes them `PENDING_REVIEW`\n * in its API and \"Pending Review\" in its activity log; both land here.\n */\nconst STATUS_WORDS: Record<string, string> = {\n pending_review: \"In review\",\n in_review: \"In review\",\n pending_process: \"Getting ready\",\n in_process: \"Getting ready\",\n processing: \"Getting ready\",\n active: \"Running\",\n enabled: \"Running\",\n with_issues: \"Has issues\",\n disapproved: \"Rejected\",\n preapproved: \"Approved\",\n pending_billing_info: \"Waiting for billing details\",\n campaign_paused: \"Paused with its campaign\",\n adset_paused: \"Paused with its ad set\",\n deleted: \"Deleted\",\n archived: \"Archived\",\n};\n\n/** `PAUSED` → \"Paused\", `LOWEST_COST_BID_STRATEGY` → \"Lowest cost\", `true` → \"On\"; plain words as they are. */\nfunction stateWords(value: string): string {\n const trimmed = value.trim();\n const status = STATUS_WORDS[trimmed.toLowerCase().replace(/[\\s-]+/g, \"_\")];\n if (status) return status;\n // A reference to another resource (`customers/1/biddingStrategies/2`) means nothing to a reader.\n if (/^[a-z]+\\/\\S+\\/\\S+/i.test(trimmed)) return \"\";\n if (/^true$/i.test(trimmed)) return \"On\";\n if (/^false$/i.test(trimmed)) return \"Off\";\n if (/^[A-Z][A-Z_]*$|^[a-z][a-z_]*$/.test(trimmed)) return humanize(trimmed.replace(/_bid_strategy$/i, \"\"));\n return trimmed;\n}\n\nconst CENTS = new Intl.NumberFormat(\"en-US\", { minimumFractionDigits: 2, maximumFractionDigits: 2 });\nconst WHOLE = new Intl.NumberFormat(\"en-US\", { maximumFractionDigits: 0 });\n\n/** An amount in its currency's sign (`MX$1,150`, `€12.50`); null when the code is not one Intl knows. */\nfunction signed(currency: string, cents: boolean): Intl.NumberFormat | null {\n try {\n const digits = cents ? 2 : 0;\n return new Intl.NumberFormat(\"en\", {\n style: \"currency\",\n currency,\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n });\n } catch {\n return null;\n }\n}\n\n/**\n * Both sides of an amount alike: whole when both are whole (\"50 → 80\"), else to\n * the cent (\"9.80 → 11.50\"); in the currency's sign when one is given.\n */\nfunction amounts(oldValue: string, newValue: string, sign = \"\"): [string | null, string | null] {\n const read = (value: string) => (value.trim() === \"\" || !Number.isFinite(Number(value)) ? null : Number(value));\n const sides = [read(oldValue), read(newValue)];\n const whole = sides.every((n) => n === null || Number.isInteger(n));\n const format = (sign === \"\" ? null : signed(sign, !whole)) ?? (whole ? WHOLE : CENTS);\n const [from, to] = sides.map((n) => (n === null ? null : format.format(n)));\n return [from ?? null, to ?? null];\n}\n\n/**\n * Both sides converted into the report's currency at its rate, each amount by\n * the screen's money rule (whole from 100 up, cents below); null when the\n * change carries no conversion or neither side is an amount.\n */\nfunction convertedAmounts(change: AdChangeFacts): { from: string | null; to: string | null } | null {\n const target = change.shownIn;\n if (!target || !signed(target.currency, false)) return null;\n const side = (value: string) => {\n if (value.trim() === \"\" || !Number.isFinite(Number(value))) return null;\n const amount = Number(value) * target.rate;\n return signed(target.currency, Math.abs(amount) < 100)?.format(amount) ?? null;\n };\n const from = side(change.oldValue);\n const to = side(change.newValue);\n return from === null && to === null ? null : { from, to };\n}\n\n/** The account's own amounts behind a converted line, for its hover. */\nfunction originalAmounts(change: AdChangeFacts, words: FieldWords): string | null {\n if (words.shape !== \"money\" || !convertedAmounts(change)) return null;\n const currency = (change.valueCurrency ?? \"\").trim().toUpperCase();\n const [from, to] = amounts(change.oldValue, change.newValue, currency);\n const said = from !== null && to !== null ? `${from} → ${to}` : (to ?? from);\n return said === null ? null : `${said} in the account's currency`;\n}\n\nfunction multiple(value: string): string | null {\n if (value.trim() === \"\") return null;\n const n = Number(value);\n return Number.isFinite(n) ? `${Math.round(n * 100)}%` : null;\n}\n\n/** \"label: old → new\", or \"label: new\" with no before; a currency once, at the end. */\nfunction moved(label: string, from: string | null, to: string | null, unit = \"\"): string {\n const suffix = unit ? ` ${unit}` : \"\";\n if (from !== null && to !== null) return `${label}: ${from} → ${to}${suffix}`;\n if (to !== null) return `${label}: ${to}${suffix}`;\n if (from !== null) return `${label} removed (was ${from}${suffix})`;\n return label;\n}\n\nfunction valueWords(words: FieldWords, change: AdChangeFacts, options: AdChangeWordsOptions): string {\n const said = valuesSaid(words, change, options);\n return said === words.label && words.shape !== \"none\" ? `${words.label} changed` : said;\n}\n\nfunction valuesSaid(words: FieldWords, change: AdChangeFacts, options: AdChangeWordsOptions): string {\n const currency = (change.valueCurrency ?? \"\").trim().toUpperCase();\n switch (words.shape) {\n case \"money\": {\n const converted = options.money === \"symbol\" ? convertedAmounts(change) : null;\n if (converted) return moved(words.label, converted.from, converted.to);\n if (options.money === \"symbol\" && signed(currency, false)) {\n return moved(words.label, ...amounts(change.oldValue, change.newValue, currency));\n }\n return moved(words.label, ...amounts(change.oldValue, change.newValue), currency);\n }\n case \"multiple\":\n return moved(words.label, multiple(change.oldValue), multiple(change.newValue));\n case \"state\":\n return moved(words.label, blankToNull(stateWords(change.oldValue)), blankToNull(stateWords(change.newValue)));\n case \"text\":\n return moved(words.label, blankToNull(change.oldValue.trim()), blankToNull(change.newValue.trim()));\n default:\n return words.label;\n }\n}\n\nfunction blankToNull(value: string): string | null {\n return value === \"\" ? null : value;\n}\n\n// ---------------------------------------------------------------------------\n// Meta's structured values\n// ---------------------------------------------------------------------------\n\n/**\n * The string literals of a JSON text, in order — read tolerantly, because a\n * stored value is cut at a length cap and may end mid-string (that one ends in \"…\").\n */\nfunction jsonStrings(text: string): string[] {\n const out: string[] = [];\n for (const match of text.matchAll(/\"((?:[^\"\\\\]|\\\\.)*)(\"|$)/g)) {\n const raw = match[1] ?? \"\";\n let value: string;\n try {\n value = JSON.parse(`\"${raw.replace(/\\\\$/, \"\")}\"`) as string;\n } catch {\n value = raw;\n }\n out.push(match[2] === \"\" ? `${value.trimEnd()}…` : value);\n }\n return out;\n}\n\n/** Meta's targeting summary, `[{content:\"Location:\", children:[\"Spain\"]}]`, as label → values; null when it is not one. */\nfunction targetingLines(value: string): Map<string, string> | null {\n if (!value.trimStart().startsWith(\"[{\")) return null;\n const lines = new Map<string, string>();\n for (const item of value.matchAll(/\\{\"content\":\"((?:[^\"\\\\]|\\\\.)*)\"(?:,\"children\":\\[([^\\]]*))?/g)) {\n const label = (jsonStrings(`\"${item[1] ?? \"\"}\"`)[0] ?? \"\").replace(/:\\s*$/, \"\").trim();\n if (label !== \"\") lines.set(label, jsonStrings(item[2] ?? \"\").join(\", \"));\n }\n return lines.size > 0 ? lines : null;\n}\n\nfunction linesText(lines: Map<string, string>): string {\n return [...lines].map(([label, value]) => (value ? `${label}: ${value}` : label)).join(\"\\n\");\n}\n\n/**\n * Meta's targeting lines by what they are to a marketer, mid-sentence: the\n * product name keeps its capitals (\"Advantage+ audience\"), the rest are plain\n * nouns (\"locations\", \"interests\").\n */\nconst TARGETING_PARTS: Record<string, string> = {\n \"advantage+ audience\": \"Advantage+ audience\",\n \"advantage audience\": \"Advantage+ audience\",\n \"advantage+ placements\": \"Advantage+ placements\",\n \"advantage detailed targeting\": \"Advantage+ interests\",\n location: \"locations\",\n locations: \"locations\",\n age: \"age\",\n gender: \"gender\",\n genders: \"gender\",\n language: \"languages\",\n languages: \"languages\",\n placements: \"placements\",\n placement: \"placements\",\n \"detailed targeting\": \"interests\",\n interests: \"interests\",\n \"custom audience\": \"custom audiences\",\n \"custom audiences\": \"custom audiences\",\n \"excluded custom audience\": \"excluded audiences\",\n \"excluded custom audiences\": \"excluded audiences\",\n \"lookalike audience\": \"lookalike audiences\",\n devices: \"devices\",\n \"people who match\": \"interests\",\n \"exclude people who match\": \"excluded interests\",\n};\n\nfunction targetingPart(label: string): string {\n const key = label.trim().toLowerCase();\n const known = TARGETING_PARTS[key];\n if (known) return known;\n // A product name (\"Advantage+ …\", \"Instagram …\") keeps its capitals; a plain word goes lower case mid-sentence.\n return /^(Advantage|Facebook|Instagram|Messenger|Threads|Audience Network)/i.test(label.trim()) ? label.trim() : key;\n}\n\nfunction targetingWords(change: AdChangeFacts): LineWords | null {\n const before = targetingLines(change.oldValue) ?? new Map<string, string>();\n const after = targetingLines(change.newValue);\n if (!after) return null;\n if (before.size === 0) return { summary: \"Targeting set\", full: linesText(after) };\n const moved = [...new Set([...before.keys(), ...after.keys()])].filter((key) => before.get(key) !== after.get(key));\n const what = [...new Set(moved.map(targetingPart))];\n const summary =\n what.length === 0\n ? \"Targeting changed\"\n : `Targeting changed: ${what.length > 2 ? `${what.slice(0, 2).join(\", \")} and ${what.length - 2} more` : what.join(\" and \")}`;\n return { summary, full: `Before\\n${linesText(before)}\\n\\nAfter\\n${linesText(after)}` };\n}\n\n/** An ad's creative as Meta logs it: a list of picture links, ids and the ad's own text. */\nfunction creativeParts(value: string): { text: string[]; media: string[] } | null {\n if (!value.trimStart().startsWith(\"[\")) return null;\n const text: string[] = [];\n const media: string[] = [];\n for (const part of jsonStrings(value)) {\n if (part.trim() === \"\") continue;\n // A picture's link is re-signed on every read: the same picture is the same path.\n if (/^https?:\\/\\//.test(part)) media.push(part.split(\"?\")[0] ?? part);\n else if (/^\\d+$/.test(part)) media.push(part);\n else text.push(part.replace(/\\\\n/g, \"\\n\"));\n }\n return { text, media };\n}\n\nfunction creativeWords(change: AdChangeFacts): LineWords | null {\n const after = creativeParts(change.newValue);\n if (!after) return null;\n const before = creativeParts(change.oldValue) ?? { text: [], media: [] };\n const textMoved = before.text.join(\"\\n\") !== after.text.join(\"\\n\");\n const mediaMoved = before.media.join(\"\\n\") !== after.media.join(\"\\n\");\n const summary =\n textMoved && mediaMoved\n ? \"Ad text and picture or video changed\"\n : textMoved\n ? \"Ad text edited\"\n : mediaMoved\n ? \"Picture or video changed\"\n : \"Ad edited\";\n return { summary, full: textMoved ? after.text.join(\"\\n\\n\") : null };\n}\n\n// ---------------------------------------------------------------------------\n\n/** The longest a value may read inline; anything longer is summarised and kept in `full`. */\nconst INLINE_LIMIT = 80;\n\n/** Several settings changed in one edit: their values do not line up one to one, so name them. */\nfunction severalWords(fields: string[]): LineWords {\n const nouns = [\n ...new Set(fields.map((field) => (wordsFor(field)?.label ?? humanize(bareField(field))).replace(/ changed$/, \"\"))),\n ];\n const [first = \"Settings\", second] = nouns;\n if (second === undefined) return { summary: `${first} changed`, full: null };\n const rest =\n nouns.length === 2 ? second.charAt(0).toLowerCase() + second.slice(1) : `${nouns.length - 1} more settings`;\n return { summary: `${first} and ${rest} changed`, full: null };\n}\n\n/**\n * A targeting edit Baker published, which stores the edit's own summary\n * (`publishedChanges.ts`): one negative keyword of a bulk add reads as itself,\n * not as the same \"Targeting changed\" as its siblings. Long ones are kept aside.\n */\nfunction bakerTargetingWords(change: AdChangeFacts): LineWords | null {\n const said = change.newValue.trim();\n if (said === \"\" || change.oldValue.trim() !== \"\") return null;\n return said.length <= INLINE_LIMIT ? { summary: said, full: null } : { summary: \"Targeting changed\", full: said };\n}\n\n/** Meta's targeting and ad copy, which arrive as JSON, and Baker's own targeting summary; null for any other field or value. */\nfunction structuredWords(bare: string, change: AdChangeFacts): LineWords | null {\n if (/target_spec$/.test(bare)) return targetingWords(change);\n if (bare === \"creative\") return creativeWords(change);\n if (bare === \"targeting\" && change.kind === \"targeting\" && change.source === \"baker\") {\n return bakerTargetingWords(change);\n }\n return null;\n}\n\nfunction lineWords(change: AdChangeFacts, options: AdChangeWordsOptions): LineWords {\n const fields = change.field\n .split(\",\")\n .map((field) => field.trim())\n .filter((field) => field !== \"\");\n if (fields.length > 1) return severalWords(fields);\n const field = fields[0] ?? \"\";\n const bare = bareField(field);\n const structured = structuredWords(bare, change);\n if (structured) return structured;\n if (field === \"\" || change.kind === \"created\") return { summary: KIND_WORDS[change.kind] ?? \"Changed\", full: null };\n const words = wordsFor(field) ?? { label: humanize(bare), shape: \"text\" as const };\n const summary = valueWords(words, change, options);\n if (summary.length <= INLINE_LIMIT + words.label.length) return { summary, full: null };\n return {\n summary: `${words.label} changed`,\n full: [change.oldValue, change.newValue].filter((value) => value !== \"\").join(\"\\n\\n→\\n\\n\"),\n };\n}\n\nexport function adChangeWords(change: AdChangeFacts, options: AdChangeWordsOptions = {}): AdChangeWords {\n const line = lineWords(change, options);\n const field = change.field.trim();\n const words =\n options.money === \"symbol\" && change.kind !== \"created\" && field !== \"\" && !field.includes(\",\")\n ? wordsFor(field)\n : null;\n return { ...line, original: words ? originalAmounts(change, words) : null };\n}\n","/**\n * Wire contract for `baker ads performance creative-assets` and the ad\n * panel's \"Every version\" gallery: every picture and video an ad runs, at the\n * largest size its platform hands over, copied into Baker's storage so the\n * agent can make variants from the originals. Read from Baker's own records\n * (`convex/adPerformance/creativeAssetStore.ts`), never from a platform.\n */\n\nimport { z } from \"zod\";\n\n/** `AD_PERFORMANCE_PLATFORMS`, repeated: `./index` re-exports this module, so it cannot be imported back at runtime. */\nconst PLATFORMS = [\"meta\", \"google\", \"linkedin\", \"x\", \"chatgpt\"] as const;\n\nexport const AD_CREATIVE_ASSET_KINDS = [\"image\", \"video\"] as const;\nexport type AdCreativeAssetKind = (typeof AD_CREATIVE_ASSET_KINDS)[number];\n\n/**\n * - `stored` — Baker holds the file (`url`).\n * - `pending` — a copy is owed and on its way.\n * - `unavailable` — the platform does not hand the file over (`note` says why); a cover may still be stored.\n * - `too_large` — larger than Baker copies; `sourceUrl` is the platform's link.\n * - `failed` — every try failed; tried again when the platform hands a new link.\n */\nexport const AD_CREATIVE_ASSET_STATUSES = [\"stored\", \"pending\", \"unavailable\", \"too_large\", \"failed\"] as const;\nexport type AdCreativeAssetStatus = (typeof AD_CREATIVE_ASSET_STATUSES)[number];\n\nconst ids = z\n .array(\n z\n .string()\n .min(1)\n .regex(/^[^,]+$/, \"ids cannot contain commas\"),\n )\n .max(200);\n\nexport const adCreativeAssetsRequestSchema = z.object({\n platforms: z.array(z.enum(PLATFORMS)).optional(),\n adAccountIds: ids.optional(),\n /** Only what these ads show. */\n adIds: ids.optional(),\n /**\n * Only what these ad groups show: the ads inside them (read from the synced\n * ads, the first 100 by spend; `more` when there are others) and, for a\n * Performance Max asset group, its own assets.\n */\n adGroupIds: ids.optional(),\n kinds: z.array(z.enum(AD_CREATIVE_ASSET_KINDS)).optional(),\n statuses: z.array(z.enum(AD_CREATIVE_ASSET_STATUSES)).optional(),\n limit: z.number().int().min(1).max(500).default(100),\n});\nexport type AdCreativeAssetsRequest = z.input<typeof adCreativeAssetsRequestSchema>;\n\n/** Where an ad shows the asset. */\nexport interface AdCreativeAssetUse {\n level: \"ad\" | \"ad_group\";\n entityId: string;\n /** What it is in the ad: `image`, `video`, `square_marketing_image`, `carousel_card`, `logo`… */\n role: string;\n /** The placements a placement version is for; null when it shows everywhere. */\n placement: string | null;\n position: number | null;\n}\n\nexport interface AdCreativeAsset {\n /** Baker's id of the asset. */\n id: string;\n platform: (typeof PLATFORMS)[number];\n adAccountId: string;\n kind: AdCreativeAssetKind;\n /** The platform's id (image hash, asset id, URN, media key). */\n platformAssetId: string;\n name: string | null;\n /** The original's size as the platform reports it (for a Meta video, the upload's, which `note` says the copy is below). */\n width: number | null;\n height: number | null;\n /** `9:16`, `1.91:1`; null without a size. */\n aspectRatio: string | null;\n durationSeconds: number | null;\n bytes: number | null;\n mimeType: string | null;\n status: AdCreativeAssetStatus;\n /** Baker's copy of the file; null until stored. Permanent. */\n url: string | null;\n /** Baker's copy of a video's cover picture. */\n posterUrl: string | null;\n /** The platform's own link to the file, which may expire; null when it gave none. */\n sourceUrl: string | null;\n /** A Google Ads video is a YouTube video: its link, since its file cannot be downloaded. */\n youtubeUrl: string | null;\n /** Why there is no copy, or what the copy is not (a Meta video's streamed quality), in plain words; null when nothing is missing. */\n note: string | null;\n uses: AdCreativeAssetUse[];\n /** How many uses there are in all (`uses` is capped). */\n useCount: number;\n firstSeenAt: number;\n lastSeenAt: number;\n}\n\nexport interface AdCreativeAssetsData {\n assets: AdCreativeAsset[];\n /** Matching assets beyond `limit`, or a read that could not cover everything asked: narrow it. */\n more: boolean;\n /** Matching assets per status (across all, not just the page). */\n counts: Record<AdCreativeAssetStatus, number>;\n}\n\nexport interface AdCreativeAssetsResponse {\n ok: true;\n data: AdCreativeAssetsData;\n}\n","/**\n * Wire contract for `baker ads performance creative-health` and the Creatives\n * view's health sections: which creatives are taking off, which active ads are\n * not earning their spend, how often a new creative becomes a winner, and how\n * much of the money goes to fresh creative. Read from Baker's ad store\n * (`convex/adPerformance/creativeHealth.ts`), never from a platform.\n *\n * Every amount sits beside its `currency`; nothing is added across currencies.\n * Windows end on each platform's last settled day (`asOf`), so results are not\n * read while they are still arriving.\n */\n\nimport { z } from \"zod\";\nimport { adReportCurrencySchema } from \"./currency\";\nimport type { AdMatureThrough } from \"./wire\";\n\n/** `AD_PERFORMANCE_PLATFORMS`, repeated: `./index` re-exports this module, so it cannot be imported back at runtime. */\nconst PLATFORMS = [\"meta\", \"google\", \"linkedin\", \"x\", \"chatgpt\"] as const;\n\nexport const AD_CREATIVE_HEALTH_SECTIONS = [\"trending\", \"poor\", \"hit_rate\", \"freshness\"] as const;\nexport type AdCreativeHealthSection = (typeof AD_CREATIVE_HEALTH_SECTIONS)[number];\n\n/** What \"new\" can mean on the freshness report: a creative at most this many days past its launch. */\nexport const AD_FRESHNESS_NEW_DAYS = [7, 14, 30] as const;\nexport type AdFreshnessNewDays = (typeof AD_FRESHNESS_NEW_DAYS)[number];\n\n/** The periods the freshness tiles are measured over, ending yesterday: yesterday, the last 7, the last 14 days. */\nexport const AD_FRESHNESS_PERIOD_DAYS = [1, 7, 14] as const;\nexport type AdFreshnessPeriodDays = (typeof AD_FRESHNESS_PERIOD_DAYS)[number];\n\n/** Days since a creative's launch, bucketed; the \"new\" choices end on a bucket edge. */\nexport const AD_CREATIVE_AGE_BUCKETS = [\"0-7\", \"8-14\", \"15-30\", \"31-60\", \"61+\"] as const;\nexport type AdCreativeAgeBucket = (typeof AD_CREATIVE_AGE_BUCKETS)[number];\n\nconst accountIds = z\n .array(\n z\n .string()\n .min(1)\n .regex(/^[^,]+$/, \"ids cannot contain commas\"),\n )\n .max(200);\n\nexport const adCreativeHealthRequestSchema = z.object({\n /** Amounts in this currency (ISO code), or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n\n platforms: z.array(z.enum(PLATFORMS)).optional(),\n adAccountIds: accountIds.optional(),\n /** `creative` counts the same picture or video once across its ads; `ad` keeps every ad apart. */\n groupBy: z.enum([\"creative\", \"ad\"]).default(\"creative\"),\n /** The reports to read; all when absent. */\n sections: z.array(z.enum(AD_CREATIVE_HEALTH_SECTIONS)).min(1).optional(),\n /** Launch months the hit rate covers, this one included. */\n months: z.number().int().min(2).max(12).default(6),\n});\nexport type AdCreativeHealthRequest = z.input<typeof adCreativeHealthRequestSchema>;\n\n/** What a creative (or ad) shows: the top-spending ad's metadata. */\nexport interface AdCreativeRef {\n groupKey: string;\n platform: string;\n adAccountId: string;\n topAdId: string;\n name: string;\n headline: string;\n thumbnailUrl: string;\n imageUrl: string;\n creativeFormat: string;\n}\n\nexport interface AdTrendingCreative extends AdCreativeRef {\n currency: string;\n /** The recent period's last day: the platform's last settled day. */\n asOf: string;\n spend: number;\n previousSpend: number;\n /** Relative (`0.4` = +40 %); null when nothing was spent in the period before. */\n spendChange: number | null;\n /** First spend inside the recent period. */\n isNew: boolean;\n /** Nothing spent in the period before, but it had run earlier. */\n restarted: boolean;\n results: number;\n costPerResult: number | null;\n /** All clicks ÷ impressions. */\n ctr: number | null;\n /** The platform's video views ÷ impressions; null where none were counted. */\n videoViewRate: number | null;\n ads: number;\n activeAds: number;\n launchDay: string | null;\n}\n\nexport interface AdCreativeTrendingData {\n periodDays: number;\n minGrowth: number;\n rows: AdTrendingCreative[];\n}\n\nexport type AdPoorPerformerReason = \"costly\" | \"no_results\";\n\nexport interface AdPoorPerformer {\n platform: string;\n adAccountId: string;\n currency: string;\n asOf: string;\n adId: string;\n adGroupId: string;\n campaignId: string;\n name: string;\n adGroupName: string;\n campaignName: string;\n headline: string;\n thumbnailUrl: string;\n imageUrl: string;\n creativeFormat: string;\n spend: number;\n results: number;\n costPerResult: number | null;\n launchDay: string;\n ageDays: number;\n /** It ran before Baker's stored history begins, so it is at least `ageDays` old. */\n ageIsLowerBound: boolean;\n reason: AdPoorPerformerReason;\n /** What it is compared with: its ad group's cost per result, or its ad account's when the ad group has no results. */\n baseline: \"ad_group\" | \"ad_account\";\n baselineCostPerResult: number;\n /** Its cost per result over the baseline's, shrunk toward 1 when results are few; null with no results. */\n costRatio: number | null;\n /** What it spent beyond what the baseline would have paid for its results. */\n excessSpend: number;\n}\n\nexport interface AdPoorPerformersData {\n windowDays: number;\n minAgeDays: number;\n /** Active ads with spend in the window that were old enough to judge. */\n checkedAds: number;\n rows: AdPoorPerformer[];\n}\n\nexport interface AdHitRateCreative extends AdCreativeRef {\n launchDay: string;\n /** Spend and results in its first days after launch (at most the cohort days, cut at `asOf`). */\n spend: number;\n results: number;\n daysObserved: number;\n winner: boolean;\n}\n\nexport interface AdHitRateMonth {\n /** `YYYY-MM`. */\n month: string;\n launches: number;\n winners: number;\n /** Some launch of the month has not had its full cohort days yet. */\n maturing: boolean;\n creatives: AdHitRateCreative[];\n}\n\nexport interface AdHitRateAccount {\n platform: string;\n adAccountId: string;\n currency: string;\n asOf: string;\n /** The ad account's spend ÷ results over the months shown; null when it had no results. */\n accountCostPerResult: number | null;\n /** The spend a launch needs within its cohort days to be a winner; null without a cost per result. */\n winnerSpend: number | null;\n months: AdHitRateMonth[];\n}\n\nexport interface AdHitRateData {\n cohortDays: number;\n winnerMultiple: number;\n /** `YYYY-MM`, oldest first. */\n months: string[];\n accounts: AdHitRateAccount[];\n}\n\nexport interface AdFreshnessTile {\n newDays: AdFreshnessNewDays;\n periodDays: AdFreshnessPeriodDays;\n from: string;\n to: string;\n spend: number;\n /** Share of spend on creatives at most `newDays` old; null with no spend. */\n freshShare: number | null;\n /** The same over the period before. */\n previousFreshShare: number | null;\n /** Spend-weighted days since launch: the average age of a unit of money spent. */\n spendWeightedAgeDays: number | null;\n freshCostPerResult: number | null;\n staleCostPerResult: number | null;\n /** Every day of the period is settled on every platform in this currency. */\n settled: boolean;\n}\n\nexport interface AdFreshnessWeek {\n from: string;\n to: string;\n spend: number;\n results: number;\n costPerResult: number | null;\n buckets: Array<{ bucket: AdCreativeAgeBucket; spend: number }>;\n freshShares: Array<{ newDays: AdFreshnessNewDays; share: number | null }>;\n settled: boolean;\n}\n\n/** Settled weeks split by how much went to fresh creative: a correlation, never a cause. */\nexport interface AdFreshnessComparison {\n newDays: AdFreshnessNewDays;\n /** Weeks in each half. */\n weeks: number;\n freshWeeksShare: number;\n staleWeeksShare: number;\n freshWeeksMedianCostPerResult: number;\n staleWeeksMedianCostPerResult: number;\n}\n\nexport interface AdFreshnessCurrency {\n currency: string;\n platforms: string[];\n tiles: AdFreshnessTile[];\n weeks: AdFreshnessWeek[];\n comparisons: AdFreshnessComparison[];\n /** Share of the weeks' spend on creatives already running when the stored history begins: their age is a lower bound. */\n beforeHistoryShare: number | null;\n}\n\nexport interface AdFreshnessData {\n /** Yesterday: the last day read. */\n asOf: string;\n currencies: AdFreshnessCurrency[];\n}\n\nexport interface AdCreativeHealthData {\n groupBy: \"creative\" | \"ad\";\n matureThrough: AdMatureThrough[];\n trending: AdCreativeTrendingData | null;\n poor: AdPoorPerformersData | null;\n hitRate: AdHitRateData | null;\n freshness: AdFreshnessData | null;\n}\n\nexport type AdCreativeHealthResponse = { ok: true; data: AdCreativeHealthData };\n","/**\n * Wire contract for the day-grain diagnostic of `baker ads performance`:\n * `anomalies` (the unusual days of each ad account's last 14 settled days,\n * what carried them and what changed near them, and whether the conversion\n * events the ads optimise for still record) and `recap` (the last days of\n * changes as a media buyer's plain sentences). Read from Baker's own store\n * (`convex/adPerformance/anomalies.ts`, `changeRecap.ts`), never from an ad\n * platform. Money sits beside its currency and is never added across\n * currencies.\n */\n\nimport { z } from \"zod\";\nimport { calendarDaySchema } from \"../calendarDays\";\nimport { adReportCurrencySchema } from \"./currency\";\n\n/** Kept apart from `./index` on purpose: that module re-exports this one, so it cannot be imported back at runtime. */\nconst DIAGNOSTIC_PLATFORMS = [\"meta\", \"google\", \"linkedin\", \"x\", \"chatgpt\"] as const;\n\nconst idList = z\n .array(\n z\n .string()\n .min(1)\n .regex(/^[^,]+$/, \"ids cannot contain commas\"),\n )\n .max(200);\n\n// --- Requests ---\n\n/**\n * `anomalies`: the last `days` settled days of every ad account (default 14),\n * ending each platform's last settled day — or `end` when named. `cpaSpike`\n * overrides how far above its usual a day's cost per result must be to count\n * (0.5 = 50 % above), for a company with a threshold of its own.\n */\nexport const adPerformanceAnomaliesRequestSchema = z.object({\n /** Amounts in this currency (ISO code), or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n\n days: z.number().int().min(7).max(28).default(14),\n end: calendarDaySchema.optional(),\n platforms: z.array(z.enum(DIAGNOSTIC_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n cpaSpike: z.number().min(0.1).max(5).optional(),\n});\nexport type AdPerformanceAnomaliesRequest = z.input<typeof adPerformanceAnomaliesRequestSchema>;\n\n/** `recap`: the changes of the last `days` days (default 7) as plain sentences. */\nexport const adPerformanceRecapRequestSchema = z.object({\n days: z.number().int().min(1).max(31).default(7),\n platforms: z.array(z.enum(DIAGNOSTIC_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n});\nexport type AdPerformanceRecapRequest = z.input<typeof adPerformanceRecapRequestSchema>;\n\n// --- Anomalies ---\n\n/** `anomaly`: an unusual stretch was found; `clear`: none; the rest say why it could not be judged. */\nexport type AdAnomalyStatus = \"anomaly\" | \"clear\" | \"too_few_results\" | \"no_spend\";\n/**\n * `no_results`: it spent with no result where several were expected;\n * `cost_spike`: results cost far more than usual; `stopped_spending`: an\n * account that spends daily spent nothing for days in a row.\n */\nexport type AdAnomalyKind = \"no_results\" | \"cost_spike\" | \"stopped_spending\";\n\nexport interface AdAnomalyDay {\n date: string;\n spend: number;\n results: number;\n costPerResult: number | null;\n /** The results the account's usual rate predicts for the day's spend. */\n expectedResults: number;\n /** The platform has finished counting the day; a day still filling in is shown, never flagged. */\n settled: boolean;\n /** Inside an unusual stretch. */\n anomalous: boolean;\n}\n\nexport interface AdAnomalySide {\n from: string;\n to: string;\n days: number;\n spend: number;\n results: number;\n costPerResult: number | null;\n}\n\n/** An ad group or ad that carried the stretch's money and moved. */\nexport interface AdAnomalyFactor {\n level: \"ad_group\" | \"ad\";\n entityId: string;\n name: string;\n campaignName: string;\n /** For an ad, its ad group; \"\" for an ad group. */\n adGroupName: string;\n spend: number;\n previousSpend: number;\n /** Relative (0.2 = +20 %); null when it spent nothing before. */\n spendChangePct: number | null;\n /** Its share of the stretch's spend. */\n shareOfSpend: number;\n results: number;\n previousResults: number;\n costPerResult: number | null;\n previousCostPerResult: number | null;\n}\n\n/** A change near the stretch that can move delivery: a large budget step, targeting, goal, status or a launch. */\nexport interface AdAnomalyChange {\n changedAt: number;\n level: string;\n entityId: string;\n entityName: string;\n kind: string;\n /** One line: what changed, by whom. */\n summary: string;\n actorKind: string;\n /** Relative budget step (0.3 = +30 %), when the change is a budget one with both amounts. */\n budgetChangePct: number | null;\n}\n\nexport interface AdAnomalyPeriod {\n kind: AdAnomalyKind;\n anomaly: AdAnomalySide;\n /** The same number of days just before it. */\n before: AdAnomalySide;\n expectedResults: number;\n /** How unlikely so few results are at the usual rate (Poisson tail). */\n pValue: number;\n headline: string;\n factors: AdAnomalyFactor[];\n changes: AdAnomalyChange[];\n}\n\nexport interface AdAnomalyAccount {\n platform: (typeof DIAGNOSTIC_PLATFORMS)[number];\n adAccountId: string;\n accountName: string;\n currency: string;\n status: AdAnomalyStatus;\n headline: string;\n /** The last settled day; days after it are shown, never flagged. */\n matureThrough: string;\n /** The settled days scanned. */\n window: AdAnomalySide;\n /** The days before the window the usual rate is taken from. */\n baseline: AdAnomalySide;\n /** The window's days, then the days still filling in, oldest first. */\n days: AdAnomalyDay[];\n /** Newest first. */\n anomalies: AdAnomalyPeriod[];\n}\n\n/** `goal`: one of the company's chosen results; `optimised`: what running ad groups optimise for; `headline`: the platform's own conversions, when neither is known. */\nexport type AdEventSource = \"goal\" | \"optimised\" | \"headline\";\n/**\n * `recording`: as often as usual; `stale`: silent for longer than its usual\n * rate allows on settled days; `quiet`: silent, but only days still filling in\n * say so; `never`: watched and not recorded in the last 90 days; `rare`: too\n * rare for a silence to mean anything.\n */\nexport type AdEventHealthStatus = \"recording\" | \"stale\" | \"quiet\" | \"never\" | \"rare\";\n\nexport interface AdEventHealthRow {\n platform: (typeof DIAGNOSTIC_PLATFORMS)[number];\n adAccountId: string;\n /** The platform's own action key (`offsite_conversion.fb_pixel_lead`); \"\" for headline conversions. */\n action: string;\n label: string;\n source: AdEventSource;\n /** Running campaigns and ad groups that optimise for it. */\n optimisedBy: number;\n /** The last day it recorded any (day grain: no time of day is stored). */\n lastDay: string | null;\n /** Its usual count per day over the four weeks up to `lastDay`. */\n usualPerDay: number | null;\n /** Days with no record since `lastDay`, up to yesterday. */\n silentDays: number;\n /** What its usual rate predicts for the spend since `lastDay`. */\n expectedSince: number;\n status: AdEventHealthStatus;\n sentence: string;\n}\n\nexport interface AdAnomalyThresholds {\n cpaSpike: number;\n pValue: number;\n minBaselineResults: number;\n factorSpendShare: number;\n factorSpendSwing: number;\n budgetShift: number;\n}\n\nexport interface AdPerformanceAnomaliesData {\n /** Yesterday: the last day shown. */\n through: string;\n thresholds: AdAnomalyThresholds;\n accounts: AdAnomalyAccount[];\n events: AdEventHealthRow[];\n}\n\n// --- Recap ---\n\n/** `created` · `turned_on` · `paused` · `removed` · `review` · `budget_up` · `budget_down` · `budget` · `edits`. */\nexport type AdRecapAction =\n | \"created\"\n | \"turned_on\"\n | \"paused\"\n | \"removed\"\n | \"review\"\n | \"budget_up\"\n | \"budget_down\"\n | \"budget\"\n | \"edits\";\n\nexport interface AdRecapLine {\n /** The UTC day of the changes. */\n day: string;\n platform: (typeof DIAGNOSTIC_PLATFORMS)[number];\n adAccountId: string;\n action: AdRecapAction;\n level: string;\n /** Entities changed. */\n count: number;\n /** For `edits`, what kinds were changed (`targeting`, `name`, …). */\n kinds: string[];\n actorKind: string;\n /** Who made them, as the platform names them; \"\" when not known. */\n actor: string;\n /** The Baker chat, when Baker published them. */\n chatTitle: string;\n sentence: string;\n entityIds: string[];\n}\n\nexport interface AdPerformanceRecapData {\n window: { from: string; to: string; days: number };\n lines: AdRecapLine[];\n /** Every change the window holds; when above what was read, the oldest were left out. */\n totalChanges: number;\n readChanges: number;\n}\n\ntype Envelope<T> = { ok: true; data: T };\nexport type AdPerformanceAnomaliesResponse = Envelope<AdPerformanceAnomaliesData>;\nexport type AdPerformanceRecapResponse = Envelope<AdPerformanceRecapData>;\n","/**\n * Wire contract for `baker ads performance health` and Measure → Ads →\n * Health: an ad account's health at a glance — spend against last month, cost\n * per result against the week before, how much budget is still learning, who\n * the ads reach (new people or people who already know the brand), how much\n * copy the top ads give the platform to test, how often the same people see\n * the ads, and the monthly spend — read from Baker's own store\n * (`convex/adPerformance/accountHealth.ts`), never from an ad platform.\n *\n * Every section answers per platform (and per currency: money is never added\n * across currencies). A platform that cannot fill a section says so in\n * `unavailable`, with the reason in plain words, instead of showing zeros.\n */\n\nimport { z } from \"zod\";\nimport { adReportCurrencySchema } from \"./currency\";\n\n/** Kept apart from `./index` on purpose: that module re-exports this one, so it cannot be imported back at runtime. */\nconst HEALTH_PLATFORMS = [\"meta\", \"google\", \"linkedin\", \"x\", \"chatgpt\"] as const;\ntype HealthPlatform = (typeof HEALTH_PLATFORMS)[number];\n\nconst idList = z\n .array(\n z\n .string()\n .min(1)\n .regex(/^[^,]+$/, \"ids cannot contain commas\"),\n )\n .max(200);\n\nexport const adPerformanceHealthRequestSchema = z.object({\n /** Amounts in this currency (ISO code), or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n\n platforms: z.array(z.enum(HEALTH_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n});\nexport type AdPerformanceHealthRequest = z.input<typeof adPerformanceHealthRequestSchema>;\n\n/**\n * Share of the last 7 days' spend in ad groups still learning: below 20 % the\n * budget runs mostly where delivery has settled; 20–50 % is worth watching\n * (avoid more big edits until it settles); above 50 % most of the money buys\n * unsettled delivery — consolidate ad groups or slow new launches.\n */\nexport const AD_LEARNING_SHARE_THRESHOLDS = { monitor: 0.2, act: 0.5 } as const;\nexport const AD_LEARNING_VERDICTS = [\"healthy\", \"monitor\", \"act\"] as const;\nexport type AdLearningVerdict = (typeof AD_LEARNING_VERDICTS)[number];\n\nexport const AD_LEARNING_STAGES = [\"learning\", \"learning_limited\", \"success\"] as const;\nexport const AD_AUDIENCE_TYPES = [\"prospecting\", \"retargeting\"] as const;\nexport const AD_AUDIENCE_SEGMENTS = [\"prospecting\", \"engaged\", \"existing\", \"unclassified\"] as const;\nexport type AdAudienceSegment = (typeof AD_AUDIENCE_SEGMENTS)[number];\n\n/** Meta lets one ad carry up to 5 primary texts and 5 headlines; an ad using all of them gives delivery the most to test. */\nexport const AD_COPY_VARIANTS_MAX = 5;\n\n/** The health sections, for `unavailable`. */\nexport const AD_HEALTH_SECTIONS = [\"learning\", \"audience\", \"copy\", \"frequency\", \"segments\"] as const;\nexport type AdHealthSection = (typeof AD_HEALTH_SECTIONS)[number];\n\n/** The sections the health checklist judges, in the order a person reads them. */\nexport const AD_HEALTH_CHECK_SECTIONS = [\"learning\", \"audience\", \"segments\", \"frequency\", \"copy\", \"traffic\"] as const;\nexport type AdHealthCheckSection = (typeof AD_HEALTH_CHECK_SECTIONS)[number];\n\n/** `act` and `look` ask for a person; `info` is a reading no rule judges; `unavailable` has nothing to read. */\nexport const AD_HEALTH_CHECK_STATES = [\"act\", \"look\", \"ok\", \"info\", \"unavailable\"] as const;\nexport type AdHealthCheckState = (typeof AD_HEALTH_CHECK_STATES)[number];\n\n/** Above this many showings a week per person, the same people may be tiring of the ads. */\nexport const AD_FREQUENCY_WEEKLY_LOOK = 3;\n/** Above this share of spend on people who already know the brand, little is finding new people. */\nexport const AD_RETARGETING_SHARE_LOOK = 0.5;\n/** Below this share of top ads using every copy slot, delivery has little text to test. */\nexport const AD_COPY_MAXIMIZED_LOOK = 0.5;\n\n/** One line of the health checklist: a section's verdict, in one sentence, over its own window. */\nexport interface AdHealthCheck {\n section: AdHealthCheckSection;\n state: AdHealthCheckState;\n title: string;\n /** The verdict in one sentence, with what to do when it asks for a person. */\n line: string;\n /** The window the section reads, in words: \"last 7 days\". */\n window: string;\n}\n\nexport interface AdHealthWindow {\n from: string;\n to: string;\n}\n\n/** Spend this month so far against the same days of last month. */\nexport interface AdHealthSpend {\n platform: HealthPlatform;\n currency: string;\n thisMonth: AdHealthWindow & { spend: number };\n lastMonth: AdHealthWindow & { spend: number };\n /** Relative, `-0.81` = 81 % less; null without spend last month. */\n change: number | null;\n}\n\n/** Cost per result over the last 7 settled days against the 7 before. */\nexport interface AdHealthCostPerResult {\n platform: HealthPlatform;\n currency: string;\n current: AdHealthWindow & { spend: number; results: number; costPerResult: number | null };\n previous: AdHealthWindow & { spend: number; results: number; costPerResult: number | null };\n change: number | null;\n}\n\n/** Trailing 30 days of traffic: what a click to the site and a thousand impressions cost. */\nexport interface AdHealthTraffic {\n platform: HealthPlatform;\n currency: string;\n window: AdHealthWindow;\n spend: number;\n impressions: number;\n linkClicks: number;\n costPerLinkClick: number | null;\n linkCtr: number | null;\n cpm: number | null;\n}\n\nexport interface AdHealthLearningGroup {\n entityId: string;\n name: string;\n campaignName: string;\n /** `learning` | `learning_limited`. */\n stage: string;\n status: string;\n spend: number;\n}\n\nexport interface AdHealthLearning {\n platform: HealthPlatform;\n currency: string;\n window: AdHealthWindow;\n /** Ad groups (Meta ad sets) or, on Google Ads, campaigns: where the platform keeps its learning status. */\n basis: \"ad_group\" | \"campaign\";\n learningSpend: number;\n limitedSpend: number;\n totalSpend: number;\n /** (learning + limited) ÷ total; null without spend. */\n share: number | null;\n verdict: AdLearningVerdict | null;\n groups: AdHealthLearningGroup[];\n}\n\nexport interface AdHealthAudienceGroup {\n entityId: string;\n name: string;\n campaignName: string;\n status: string;\n /** `prospecting` | `retargeting`; \"\" when unknown. */\n type: string;\n ageRange: string;\n audiences: string;\n exclusions: string;\n spend: number;\n}\n\nexport interface AdHealthAudience {\n platform: HealthPlatform;\n currency: string;\n window: AdHealthWindow;\n prospectingSpend: number;\n retargetingSpend: number;\n /** Spend in ad groups whose targeting Baker has not read yet. */\n unknownSpend: number;\n totalSpend: number;\n /** Where the platform split the same spend by customer segment (Meta Advantage+ sales): shares of spend. */\n segmentShares: Array<{ segment: AdAudienceSegment; share: number }> | null;\n groups: AdHealthAudienceGroup[];\n /** Excluded audiences by how many of the ad groups above exclude them, most first. */\n topExclusions: Array<{ name: string; adGroups: number }>;\n}\n\nexport interface AdHealthCopyAd {\n entityId: string;\n name: string;\n adGroupName: string;\n spend: number;\n primaryTexts: number;\n headlines: number;\n maximized: boolean;\n}\n\nexport interface AdHealthCopy {\n platform: HealthPlatform;\n currency: string;\n window: AdHealthWindow;\n ads: AdHealthCopyAd[];\n maximized: number;\n}\n\nexport interface AdHealthReachWeek {\n /** The Monday the week starts. */\n week: string;\n reach: number;\n impressions: number;\n /** Impressions ÷ people reached that week. */\n frequency: number | null;\n /** People reached ÷ impressions: the share of impressions that were someone's first that week. */\n firstTimeRate: number | null;\n /** The current week, still running. */\n partial: boolean;\n}\n\nexport interface AdHealthFrequency {\n platform: HealthPlatform;\n weeks: AdHealthReachWeek[];\n /** Over the whole weeks only. */\n averageFrequency: number | null;\n averageFirstTimeRate: number | null;\n /** Reach of several ad accounts is added: someone reached by two counts twice. */\n accounts: number;\n}\n\nexport interface AdHealthMonth {\n /** `YYYY-MM`. */\n month: string;\n spend: number;\n results: number;\n costPerResult: number | null;\n /** The current month, still running. */\n partial: boolean;\n /** Results of its last days may still arrive. */\n settled: boolean;\n}\n\nexport interface AdHealthMonthly {\n platform: HealthPlatform;\n currency: string;\n months: AdHealthMonth[];\n}\n\nexport interface AdHealthSegmentCell {\n segment: AdAudienceSegment;\n spend: number;\n share: number | null;\n results: number;\n costPerResult: number | null;\n /** Result value ÷ spend; null where no value is counted. */\n roas: number | null;\n}\n\nexport interface AdHealthSegmentWeek {\n week: string;\n partial: boolean;\n totalSpend: number;\n segments: AdHealthSegmentCell[];\n}\n\nexport interface AdHealthSegments {\n platform: HealthPlatform;\n currency: string;\n weeks: AdHealthSegmentWeek[];\n /** The largest change in a segment's share of spend between the first and last whole week, in words; null when nothing moved. */\n moving: string | null;\n}\n\nexport interface AdPerformanceHealthData {\n /** The newest whole day read. */\n asOf: string;\n platforms: HealthPlatform[];\n spend: AdHealthSpend[];\n costPerResult: AdHealthCostPerResult[];\n traffic: AdHealthTraffic[];\n learning: AdHealthLearning[];\n audience: AdHealthAudience[];\n copy: AdHealthCopy[];\n frequency: AdHealthFrequency[];\n monthly: AdHealthMonthly[];\n segments: AdHealthSegments[];\n /** What a platform cannot fill, and why, in plain words. */\n unavailable: Array<{ section: AdHealthSection; platform: HealthPlatform; reason: string }>;\n /** One verdict per section, problems first (`convex/adPerformance/healthChecks.ts`). */\n checks: AdHealthCheck[];\n}\n\nexport interface AdPerformanceHealthResponse {\n ok: true;\n data: AdPerformanceHealthData;\n}\n","/**\n * Wire contract for what the winning-ads library knows about the creatives a\n * company launched (`baker ads performance families`, and the `library` of each\n * row of `creatives`).\n *\n * The library scrapes the brand's own public ads, groups them into families of\n * the same creative and reads each the way it reads any winning ad: hook,\n * angle, copy framework, offer, style. Baker links every launched creative to\n * the family it is (`convex/adPerformance/libraryMatch.ts`), so the ad\n * accounts' real spend and results sit next to the library's reading — and\n * next to its guess at what won.\n */\n\nimport { z } from \"zod\";\nimport {\n AD_PERFORMANCE_PLATFORMS,\n type AdMatureThrough,\n type AdMetrics,\n type AdRatios,\n type AdReportWindow,\n adPerformanceScopeFields,\n scopeRules,\n} from \"./wire\";\n\n/** What the library read in a creative, in its own vocabulary (null where it read nothing). */\nexport interface AdCreativeAnalysis {\n /** The creative idea in a sentence. */\n concept: string | null;\n /** The angle in the ad's words, and its type (`save_money`, `status`, …). */\n angle: string | null;\n angleType: string | null;\n /** How it opens (`question`, `bold_claim`, `pattern_interrupt`, …) and with what. */\n hook: string | null;\n hookOpener: string | null;\n /** The copy framework (`PAS`, `AIDA`, `before_after`, …). */\n framework: string | null;\n /** What makes the promise work (`AI_automated`, `proprietary_method`, …). */\n mechanism: string | null;\n /** Who it speaks to: awareness stage, funnel stage and how cold the audience is. */\n awareness: string | null;\n funnel: string | null;\n temperature: string | null;\n /** What it offers (`free_trial`, `discount`, `calculator`, …) and asks for. */\n offer: string | null;\n cta: string | null;\n /** A video's style (`talking_head`, `ugc`, …) or a picture's layout (`us_vs_them`, …), and who is on screen. */\n style: string | null;\n creator: string | null;\n}\n\n/**\n * How sure Baker is which family a creative is:\n * - `linked`: the words, the page, the start day and the size all point to one.\n * - `likely`: one family is ahead, but not by much.\n * - `ambiguous`: two or more fit equally — videos launched together under the same words.\n * - `not_found`: nothing in the library is it (never published, not public, or not read yet).\n */\nexport const AD_LIBRARY_LINK_STATUSES = [\"linked\", \"likely\", \"ambiguous\", \"not_found\"] as const;\nexport type AdLibraryLinkStatus = (typeof AD_LIBRARY_LINK_STATUSES)[number];\n\n/** Where a launched creative sits in the library. */\nexport interface AdCreativeLibraryLink {\n status: AdLibraryLinkStatus;\n /** A person settled it; Baker's reading no longer moves it. */\n chosen: boolean;\n advertiserId: string;\n familyId: string | null;\n /** The library ad that matched best: open it with `baker winning-ads content <id>`. */\n adId: string | null;\n /** The library's copy of that ad's picture or video. */\n media: { url: string; kind: string | null } | null;\n /** The other families still possible when it is not settled. */\n otherFamilies: number;\n /**\n * Why nothing in the library is it, when nothing is: the brand has no ad\n * there yet, or it ran at a time the library has not read (both: Baker reads\n * it again for new ads), no ad says the same words, or the closest is not\n * close enough.\n */\n notFoundReason: \"no_library_ads\" | \"words_differ\" | \"not_live_together\" | \"too_unlike\" | null;\n analysis: AdCreativeAnalysis | null;\n /** The library's own guess: its winner score (0–1, a winner from 0.4) and the family's size. */\n libraryWinnerScore: number | null;\n libraryWinner: boolean | null;\n familySize: number | null;\n}\n\n/** What a group of creatives is grouped by. */\nexport const AD_CREATIVE_GROUPS = [\n \"family\",\n \"hook\",\n \"angle\",\n \"framework\",\n \"offer\",\n \"awareness\",\n \"style\",\n \"creator\",\n \"mechanism\",\n] as const;\nexport type AdCreativeGroup = (typeof AD_CREATIVE_GROUPS)[number];\n\nexport const adPerformanceFamiliesRequestSchema = z\n .object({\n ...adPerformanceScopeFields,\n /** `family` (one row per library family), or a part of the reading: `hook`, `angle`, `framework`, … */\n by: z.enum(AD_CREATIVE_GROUPS).default(\"family\"),\n /** Leave out creatives that spent less than this in the window. */\n minSpend: z.number().min(0).default(0),\n limit: z.number().int().min(1).max(100).default(25),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceFamiliesRequest = z.input<typeof adPerformanceFamiliesRequestSchema>;\n\n/**\n * Whether the library's guess agrees with the money, for one family:\n * `both` won, the library's guess only (`library_only`), the money only\n * (`ours_only`), `neither`; `unknown` while either side is too thin to say.\n */\nexport const AD_WINNER_AGREEMENTS = [\"both\", \"library_only\", \"ours_only\", \"neither\", \"unknown\"] as const;\nexport type AdWinnerAgreement = (typeof AD_WINNER_AGREEMENTS)[number];\n\n/** One creative of a group, to show and open on its own. */\nexport interface AdCreativeGroupMember {\n groupKey: string;\n platform: string;\n /** Its highest-spending ad, the one its detail opens on. */\n topAdId: string;\n /** That ad's name, as Campaigns → Ads lists it. */\n name: string;\n headline: string;\n thumbnailUrl: string;\n imageUrl: string;\n creativeFormat: string;\n /** Some ad using it still runs. */\n running: boolean;\n spend: number;\n results: number;\n costPerResult: number | null;\n}\n\nexport interface AdCreativeGroupRow {\n /** The family id, or the value grouped by (`question`); `unread` for creatives the library has not read. */\n key: string;\n label: string;\n /** A family's reading; null for a group of several families. */\n analysis: AdCreativeAnalysis | null;\n currency: string;\n creatives: number;\n activeCreatives: number;\n metrics: AdMetrics;\n ratios: AdRatios;\n /** Its share of the window's spend and results across every group in the same currency. */\n spendShare: number;\n resultsShare: number | null;\n /** Creatives that beat, and that fell behind, their ad-group peers. */\n abovePeers: number;\n belowPeers: number;\n /** The highest-spending creative, to show and to open, and its library ad when it has one. */\n top: {\n groupKey: string;\n platform: string;\n /** Its highest-spending ad, the one its detail opens on. */\n topAdId: string;\n /** Its top ad's name, as Campaigns → Ads lists it. */\n name: string;\n headline: string;\n thumbnailUrl: string;\n libraryAdId: string | null;\n libraryMedia: { url: string; kind: string | null } | null;\n };\n /** Its creatives, highest spend first (the first 24). */\n members: AdCreativeGroupMember[];\n /** The library's side: how many of its families and ads this group spans, and its best winner score. */\n library: { families: number; winners: number; bestWinnerScore: number | null };\n /** Families only; null for any other grouping. */\n agreement: AdWinnerAgreement | null;\n}\n\nexport interface AdLibraryCoverage {\n /** Creatives that spent in the window, and how each sits in the library. */\n creatives: number;\n linked: number;\n likely: number;\n ambiguous: number;\n notFound: number;\n /** Not checked against the library yet. */\n unchecked: number;\n /** The window's spend on creatives linked or likely, as a share of all of it; null when that spend is in more than one currency. */\n linkedSpendShare: number | null;\n}\n\n/** The company's own brand in the library: what the link reads from. */\nexport interface AdOwnLibraryBrand {\n advertiserId: string;\n label: string;\n /** `scanning` while the library is still collecting its ads. */\n status: \"ready\" | \"scanning\";\n /** The platforms its accounts are in the library on; creatives elsewhere stay unchecked. */\n platforms: string[];\n libraryAds: number | null;\n libraryFamilies: number | null;\n /** When creatives were last matched against it (ms), null before the first time. */\n linkedAt: number | null;\n}\n\nexport interface AdPerformanceFamiliesData {\n window: AdReportWindow;\n matureThrough: AdMatureThrough[];\n by: AdCreativeGroup;\n /** Null until the brand's own ads are in the library. */\n brand: AdOwnLibraryBrand | null;\n coverage: AdLibraryCoverage;\n rows: AdCreativeGroupRow[];\n}\n\nexport type AdPerformanceFamiliesResponse = { ok: true; data: AdPerformanceFamiliesData };\n\nconst creativeKey = z.string().trim().min(1).max(300);\n\n/**\n * `baker ads performance families choices`: per launched creative (its key, as\n * `creatives` lists it in `groupKey`), the library families it may be.\n */\nexport const adLibraryChoicesRequestSchema = z.object({\n creatives: z.array(creativeKey).min(1).max(50),\n /** Leave out to find each creative on whichever platform has it. */\n platform: z.enum(AD_PERFORMANCE_PLATFORMS).optional(),\n});\nexport type AdLibraryChoicesRequest = z.input<typeof adLibraryChoicesRequestSchema>;\n\n/** Why the best family fits: how alike the words are (0–1), the landing page, the start days apart, the format. */\nexport interface AdLibraryEvidence {\n copy: number;\n landing: \"same\" | \"same_site\" | \"different\" | \"unknown\";\n startGapDays: number | null;\n format: \"same\" | \"compatible\" | \"different\";\n size: number | null;\n}\n\n/** One family a creative may be, best first. */\nexport interface AdLibraryFamilyChoice {\n familyId: string;\n /** The library ad that matched: open it with `baker winning-ads content <id>`. */\n adId: string;\n /** How well it fits, 0–1. */\n score: number;\n /** The creative idea in the library's words, else its headline. */\n concept: string | null;\n headline: string;\n mediaUrl: string | null;\n mediaKind: string | null;\n firstSeen: string | null;\n}\n\nexport type AdLibraryChoice =\n | {\n found: true;\n platform: (typeof AD_PERFORMANCE_PLATFORMS)[number];\n creativeKey: string;\n status: AdLibraryLinkStatus;\n /** A person settled it. */\n chosen: boolean;\n /** The family it stands for now: a person's choice, else Baker's reading. */\n familyId: string | null;\n evidence: AdLibraryEvidence | null;\n notFoundReason: AdCreativeLibraryLink[\"notFoundReason\"];\n families: AdLibraryFamilyChoice[];\n }\n | { found: false; creativeKey: string; platform?: (typeof AD_PERFORMANCE_PLATFORMS)[number] };\n\nexport interface AdLibraryChoicesData {\n creatives: AdLibraryChoice[];\n}\nexport type AdLibraryChoicesResponse = { ok: true; data: AdLibraryChoicesData };\n\n/**\n * `baker ads performance families link`: stage which library family a\n * launched creative is — one family, not in the library, or back to Baker's\n * own reading (`auto`). Applied when the chat is published.\n */\nexport const adLibraryLinkStageRequestSchema = z\n .object({\n chatId: z.string().min(1),\n creativeKey,\n platform: z.enum(AD_PERFORMANCE_PLATFORMS).optional(),\n /** What the creative is called, for the person reviewing: its name in `creatives`. */\n label: z\n .string({\n error:\n \"say what the creative is called (its name in baker ads performance creatives): the person reviewing knows it by that\",\n })\n .trim()\n .min(1)\n .max(200),\n familyId: z.string().trim().min(1).max(300).optional(),\n notInLibrary: z.boolean().optional(),\n auto: z.boolean().optional(),\n })\n .refine(\n (body) =>\n [body.familyId !== undefined, body.notInLibrary === true, body.auto === true].filter(Boolean).length === 1,\n {\n message: \"Pick one: a family id (--family), --not-in-library, or --auto to hand it back to Baker.\",\n },\n );\nexport type AdLibraryLinkStageRequest = z.input<typeof adLibraryLinkStageRequestSchema>;\n","/**\n * Wire contract for `baker ads performance live-in`: which live campaigns use\n * a landing (send people to it) or a creative (show it in an ad), read from\n * Baker's synced ad data (`convex/adPerformance/liveIn.ts`), never from a\n * platform. Asked before changing a landing or a creative, because a change\n * there changes what those campaigns show.\n */\n\nimport { z } from \"zod\";\n\n/** `AD_PERFORMANCE_PLATFORMS`, repeated: `./index` re-exports this module, so it cannot be imported back at runtime. */\nconst PLATFORMS = [\"meta\", \"google\", \"linkedin\", \"x\", \"chatgpt\"] as const;\ntype Platform = (typeof PLATFORMS)[number];\n\nconst slug = z\n .string()\n .trim()\n .min(1)\n .max(200)\n .regex(/^[^/\\s]+(\\/[^/\\s]+)*$/, \"a slug has no spaces\");\n\nexport const adPerformanceLiveInRequestSchema = z.object({\n /** Only this landing (its slug, as in `src/pages/<slug>/`). */\n landing: slug.optional(),\n /** Only this creative (its slug, as in `src/creatives/<slug>/`). */\n creative: slug.optional(),\n});\nexport type AdPerformanceLiveInRequest = z.input<typeof adPerformanceLiveInRequestSchema>;\n\nexport interface LiveInMoney {\n currency: string;\n amount: number;\n}\n\n/** A live campaign sending people to a landing. */\nexport interface LiveInLandingCampaign {\n platform: Platform;\n campaignId: string;\n name: string;\n /** Live ads, Performance Max asset groups and keywords in it whose page is the landing. */\n ads: number;\n assetGroups: number;\n keywords: number;\n spend30d: LiveInMoney[];\n}\n\nexport interface LiveInLanding {\n slug: string;\n campaigns: LiveInLandingCampaign[];\n}\n\n/** A live campaign with ads showing a creative. */\nexport interface LiveInCreativeCampaign {\n platform: Platform;\n campaignId: string;\n name: string;\n /** Its live ads (and asset groups) showing the creative, as far as Baker keeps them. */\n ads: Array<{ id: string; name: string; adGroupName: string; version: number | null }>;\n}\n\nexport interface LiveInCreative {\n slug: string;\n title: string;\n /** Live ads showing it, across every picture or video linked to it. */\n liveAds: number;\n platforms: Platform[];\n /** The versions of it the live ads show (\"Version N\" on its page); empty when only its library picture is. */\n versions: number[];\n /** Some link is a close look-alike rather than the same picture: say \"likely\". */\n likely: boolean;\n campaigns: LiveInCreativeCampaign[];\n /** The live ads' last 30 days of spend, per currency. */\n spend30d: LiveInMoney[];\n}\n\nexport interface AdPerformanceLiveInData {\n landings: LiveInLanding[];\n creatives: LiveInCreative[];\n}\n\nexport interface AdPerformanceLiveInResponse {\n ok: true;\n data: AdPerformanceLiveInData;\n}\n","/**\n * Wire contract for the people side of `baker ads performance`: who each\n * campaign, ad set and ad brought, how far up the Company's own outcome ladder\n * they got, at what cost per step, and who they are — read from Baker's own\n * store (`convex/adPerformance/people.ts`), never from an ad platform.\n *\n * The vocabulary is fixed (ADR 0012): a person is credited to **one** entity —\n * the one that **brought** them (`touch: \"first\"`) or their **last paid\n * touch** before they became a lead (`touch: \"last\"`, the default). Never\n * \"attributed revenue\", never ROI. Money sits beside its currency and is never\n * added across currencies; every count is of people, never a person.\n */\n\nimport { z } from \"zod\";\nimport { calendarDaySchema } from \"../calendarDays\";\nimport { adReportCurrencySchema } from \"./currency\";\nimport { scopeRules } from \"./wire\";\n\n/** Kept apart from `./index` on purpose: that module re-exports this one, so it cannot be imported back at runtime. */\nconst PEOPLE_PLATFORMS = [\"meta\", \"google\", \"linkedin\", \"x\", \"chatgpt\"] as const;\nconst PEOPLE_MAX_DAYS = 1130;\n\nexport const AD_PEOPLE_LEVELS = [\"campaign\", \"ad_group\", \"ad\"] as const;\nexport type AdPeopleLevel = (typeof AD_PEOPLE_LEVELS)[number];\n\nexport const AD_PEOPLE_TOUCHES = [\"first\", \"last\"] as const;\nexport type AdPeopleTouch = (typeof AD_PEOPLE_TOUCHES)[number];\n\n/** The persona questions a Company's Form fields can answer. */\nexport const AD_PERSONA_FIELD_DIMENSIONS = [\n \"role\",\n \"seniority\",\n \"company_size\",\n \"industry\",\n \"use_case\",\n \"heard_from\",\n \"budget\",\n \"country\",\n] as const;\n/** Every way people can be split: the Form-answered ones, plus the address kind and the visit's country and device. */\nexport const AD_PERSONA_DIMENSIONS = [...AD_PERSONA_FIELD_DIMENSIONS, \"email_kind\", \"visit_country\", \"device\"] as const;\nexport type AdPersonaDimension = (typeof AD_PERSONA_DIMENSIONS)[number];\n\n/** Why a read has no people: the Company's measurement setting keeps no one. */\nexport const AD_PEOPLE_NOT_COLLECTED_MESSAGE =\n \"This company's measurement setting keeps no people-level data (only totals, or nothing), so Baker cannot say who the ads brought.\";\n\n// --- Requests ---\n\nconst idList = z\n .array(\n z\n .string()\n .min(1)\n .regex(/^[^,]+$/, \"ids cannot contain commas\"),\n )\n .max(200);\n\nconst scopeFields = {\n days: z.number().int().min(1).max(PEOPLE_MAX_DAYS).optional(),\n start: calendarDaySchema.optional(),\n end: calendarDaySchema.optional(),\n platforms: z.array(z.enum(PEOPLE_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n campaignIds: idList.optional(),\n /** Ad sets (ad groups) to read inside: their ads, or the ad sets themselves. */\n adGroupIds: idList.optional(),\n /** Amounts in this currency (ISO code), or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n level: z.enum(AD_PEOPLE_LEVELS).default(\"campaign\"),\n touch: z.enum(AD_PEOPLE_TOUCHES).default(\"last\"),\n};\n\nexport const adPeopleRequestSchema = z\n .object({ ...scopeFields, limit: z.number().int().min(1).max(500).default(50) })\n .superRefine(scopeRules);\nexport type AdPeopleRequest = z.input<typeof adPeopleRequestSchema>;\n\nexport const adPersonasRequestSchema = z\n .object({\n ...scopeFields,\n dimension: z.enum(AD_PERSONA_DIMENSIONS),\n /** How many distinct answers to name before the rest read \"other\". */\n top: z.number().int().min(1).max(30).default(12),\n })\n .superRefine(scopeRules);\nexport type AdPersonasRequest = z.input<typeof adPersonasRequestSchema>;\n\n/** The ladder and persona-field reads look back this many days for what the Company records. */\nexport const adPeopleSettingsRequestSchema = z.object({ days: z.number().int().min(7).max(300).default(90) });\nexport type AdPeopleSettingsRequest = z.input<typeof adPeopleSettingsRequestSchema>;\n\n// --- Responses ---\n\nexport interface AdPeopleWindow {\n from: string;\n to: string;\n days: number;\n}\n\nexport interface AdMoney {\n currency: string;\n amount: number;\n}\n\nexport interface AdLadderStage {\n name: string;\n /** Event keys, `<key>|<property>=<value>`, `@identified` or `@crm_value`. */\n members: string[];\n}\n\nexport interface AdOutcomeLadder {\n stages: AdLadderStage[];\n /** Nobody chose one: \"identified\" → \"an amount from a CRM\". */\n isDefault: boolean;\n}\n\n/** One step of the ladder for one entity. */\nexport interface AdPeopleStage {\n /** 1 is the lead. */\n index: number;\n name: string;\n people: number;\n /** Of the people who became leads, the share who reached this step; null for the lead itself or with no leads. */\n perLead: number | null;\n /** Spend over people at this step; null without spend or people. In the entity's currency. */\n costPer: number | null;\n /** The step's amounts — each person's largest, per currency. */\n value: AdMoney[];\n /** Days from the credited visit to the step: median and 75th percentile; null when nobody reached it. */\n medianDays: number | null;\n p75Days: number | null;\n}\n\nexport interface AdPeopleRow {\n platform: string;\n /** `\"\"` on an untagged row. */\n entityId: string;\n name: string;\n /** The entity is in Baker's store (its id names a campaign, ad set or ad Baker synced). */\n known: boolean;\n /** Where it sits: its campaign and ad set, ids and names; `\"\"` above that level or when not synced. */\n campaignId: string;\n campaignName: string;\n adGroupId: string;\n adGroupName: string;\n currency: string;\n spend: number;\n paidSessions: number;\n people: number;\n identifiedPeople: number;\n stages: AdPeopleStage[];\n /** Deals at CRM companies whose domain a credited person's work address named: opened or won after the visit. Never added to the people. */\n companyDeals: { opened: number; won: number; wonValue: AdMoney[] };\n}\n\nexport interface AdPeopleCoverage {\n /** Paid visits in the window, every platform read. */\n paidSessions: number;\n /** Of them, the ones whose id names an entity in the store. */\n resolvedSessions: number;\n resolvedShare: number | null;\n /** People who became leads in the window. */\n leads: number;\n /** Of them, the ones with a paid visit in the 90 days before. */\n leadsWithPaidTouch: number;\n paidTouchShare: number | null;\n /** Of them, the ones whose paid visit carried an id. */\n leadsWithTaggedTouch: number;\n taggedTouchShare: number | null;\n}\n\nexport interface AdPeopleMaturity {\n index: number;\n name: string;\n /** Days to the step on the Company's own history (the last 180 days); null when too few reached it. */\n medianDays: number | null;\n p75Days: number | null;\n /** People the lag was measured on. */\n measuredOn: number;\n /** Visits from this day on have not had the usual time to reach the step: read them as early, not as failing. */\n maturingFrom: string | null;\n}\n\nexport interface AdPeopleData {\n collected: boolean;\n /** Why not, in product words, when `collected` is false. */\n notCollectedReason: string | null;\n window: AdPeopleWindow;\n /** Visits are kept 400 days; a longer window was cut, and `window` is what was read. */\n windowClipped: boolean;\n level: AdPeopleLevel;\n touch: AdPeopleTouch;\n ladder: AdOutcomeLadder;\n rows: AdPeopleRow[];\n /** Per platform: people from paid visits carrying no id at the level. */\n untagged: AdPeopleRow[];\n coverage: AdPeopleCoverage;\n maturity: AdPeopleMaturity[];\n /** People credited across every entity and the untagged rows. */\n totalPeople: number;\n}\n\nexport interface AdPersonaValue {\n /** The answer as most people wrote it. */\n value: string;\n kind: \"answer\" | \"not_answered\" | \"other\";\n people: number;\n /** People per ladder step, index 0 the lead. */\n stagePeople: number[];\n}\n\nexport interface AdPersonaRow {\n platform: string;\n entityId: string;\n name: string;\n people: number;\n values: AdPersonaValue[];\n}\n\nexport interface AdPersonasData {\n collected: boolean;\n notCollectedReason: string | null;\n window: AdPeopleWindow;\n windowClipped: boolean;\n level: AdPeopleLevel;\n touch: AdPeopleTouch;\n dimension: AdPersonaDimension;\n /** The Form fields read for it (empty for the address, country and device). */\n fieldKeys: string[];\n /** The persona map in force was suggested from the field names, not chosen by a person. */\n fieldsSuggested: boolean;\n ladderStages: string[];\n rows: AdPersonaRow[];\n}\n\nexport interface AdOutcomeCandidate {\n /** An event key, `@identified` or `@crm_value`. */\n member: string;\n name: string;\n /** The CRM source (a HubSpot Source) that posted it, when one did. */\n crmSource: string;\n fromServer: boolean;\n isConversion: boolean;\n people: number;\n events: number;\n withValue: number;\n /** A HubSpot Source's stage values seen on it, each usable as `<member>|hubspot_value=<value>`. */\n stageValues: string[];\n /** The ladder step it counts for today, if any. */\n inStage: string | null;\n}\n\nexport interface AdPeopleLadderData {\n ladder: AdOutcomeLadder;\n window: AdPeopleWindow;\n candidates: AdOutcomeCandidate[];\n}\n\nexport interface AdPersonaFieldEntry {\n dimension: (typeof AD_PERSONA_FIELD_DIMENSIONS)[number];\n fieldKeys: string[];\n}\n\nexport interface AdPersonaFieldCandidate {\n key: string;\n answers: number;\n /** Answers kept sealed (they identify the person). */\n masked: number;\n distinctValues: number;\n flows: string[];\n /** Answers given by at least three people. */\n topValues: Array<{ value: string; people: number }>;\n /** The question Baker suggests it answers; null when none or when it is mostly sealed. */\n suggested: (typeof AD_PERSONA_FIELD_DIMENSIONS)[number] | null;\n}\n\nexport interface AdPersonaFieldsData {\n fields: AdPersonaFieldEntry[];\n /** No map chosen: `fields` is Baker's suggestion. */\n suggested: boolean;\n window: AdPeopleWindow;\n candidates: AdPersonaFieldCandidate[];\n}\n\ntype Envelope<T> = { ok: true; data: T };\nexport type AdPeopleResponse = Envelope<AdPeopleData>;\nexport type AdPersonasResponse = Envelope<AdPersonasData>;\nexport type AdPeopleLadderResponse = Envelope<AdPeopleLadderData>;\nexport type AdPersonaFieldsResponse = Envelope<AdPersonaFieldsData>;\n","/**\n * Wire contract for the Google Search reports of `baker ads performance`:\n * brand against non-brand (`brand-split`), where the ads show and why they\n * miss searches (`impression-share`), and what Google thinks of the keywords\n * and the pages they lead to (`keyword-quality`), plus what the company\n * plans to spend a month and how it is pacing (`budgets`). Read from Baker's\n * own store (`convex/adPerformance/searchReports.ts`, `monthlyBudgets.ts`);\n * nothing here calls Google.\n *\n * Brand, competitor and non-brand are decided per search term and keyword by\n * Baker's decision model against the company's brand and competitor names,\n * and per campaign from what its keywords spent on (or its name); a person's\n * choice always wins (`segments set`).\n */\n\nimport { z } from \"zod\";\nimport type { AdAttentionItem } from \"./attention\";\nimport { adReportCurrencySchema } from \"./currency\";\nimport type { AdGoalStatus, AdResolvedGoalTarget, AdTargetFocus } from \"./targets\";\nimport {\n AD_PERFORMANCE_PLATFORMS,\n type AdBrandSegment,\n type AdDayWindow,\n type AdDeltas,\n type AdEntityRow,\n type AdMatureThrough,\n type AdMetrics,\n type AdPlatformScore,\n type AdRatios,\n type AdReportWindow,\n type AdSearchTermRow,\n type AdTrendPoint,\n adPerformanceScopeFields,\n idList,\n scopeRules,\n startedMonthSchema,\n} from \"./wire\";\n\n/** The scope without `platforms`: these reads are Google Ads only, so another platform is never a choice. */\nconst { platforms: _platforms, ...googleScopeFields } = adPerformanceScopeFields;\n\n// --- Brand split ---\n\nexport const adPerformanceBrandSplitRequestSchema = z\n .object({\n ...googleScopeFields,\n /** Months of history the trend draws, ending with the current one. */\n months: z.number().int().min(1).max(13).default(6),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceBrandSplitRequest = z.input<typeof adPerformanceBrandSplitRequestSchema>;\n\n/** A target for one segment's cost per result or return, company-wide. */\nexport interface AdSegmentTarget {\n segment: \"brand\" | \"competitor\" | \"non_brand\";\n metric: AdTargetFocus;\n value: number;\n /** Null for a return, which is a ratio. */\n currency: string | null;\n}\n\nexport interface AdBrandSplitSegment {\n segment: AdBrandSegment;\n currency: string;\n metrics: AdMetrics;\n ratios: AdRatios;\n /** Its share of the period's spend in this currency. */\n spendShare: number | null;\n /** Its settled days against as many days before them; null when nothing compares. */\n comparison: { previous: AdMetrics; deltas: AdDeltas; impressionSharePoints: number | null } | null;\n /**\n * The target that judges it, in `currency` (null value: set, but no rate\n * compares it): its own (Goals → Search split), else the account's, else\n * the company default — `source` says which.\n */\n target: AdResolvedGoalTarget | null;\n status: AdGoalStatus;\n}\n\nexport interface AdBrandSplitPoint {\n /** The first day of the month. */\n bucket: string;\n segment: AdBrandSegment;\n currency: string;\n metrics: AdMetrics;\n ratios: AdRatios;\n /** Every day of the month has settled. */\n mature: boolean;\n}\n\nexport interface AdPerformanceBrandSplitData {\n window: AdReportWindow;\n /** \"Are we paying for our own brand name?\", answered in one line (`brandAnswer`). */\n answer: { says: \"yes\" | \"no\"; sentence: string };\n /** Search terms a person already chose a segment for, newest first: no longer asked about. */\n reviewed: { count: number; rows: Array<{ term: string; segment: string; setAt: number }> };\n /** The settled part of the window compared with as many days before; null when nothing has settled. */\n comparison: { current: AdDayWindow; previous: AdDayWindow } | null;\n segments: AdBrandSplitSegment[];\n trend: AdBrandSplitPoint[];\n /** Brand searches bought by non-brand or competitor campaigns: brand traffic paid at another campaign's price. */\n leakage: { rows: AdSearchTermRow[]; totalRows: number; spend: Array<{ currency: string; amount: number }> };\n /** Search terms Baker was unsure about and nobody has chosen for yet: a person's choice settles them. */\n unsure: { rows: AdSearchTermRow[]; totalRows: number };\n /** What decides brand and competitor searches now. */\n names: { brandNames: string[]; brandNamesDefault: boolean; competitorNames: string[]; followedCompetitors: string[] };\n /** Some Search campaigns spent before Baker sorted them: their spend shows as `unsorted` until it does. */\n stillSorting: boolean;\n matureThrough: AdMatureThrough[];\n}\n\n// --- Impression share ---\n\nexport const adPerformanceImpressionShareRequestSchema = z\n .object({\n ...googleScopeFields,\n limit: z.number().int().min(1).max(200).default(50),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceImpressionShareRequest = z.input<typeof adPerformanceImpressionShareRequestSchema>;\n\n/** One Search campaign's share of the searches it could have shown on, and where it showed. */\nexport interface AdSearchShare {\n impressionShare: number | null;\n lostShareBudget: number | null;\n lostShareRank: number | null;\n /** Of its impressions: above the organic results, and first of all. Null before Baker measured them. */\n topImpressionRate: number | null;\n absoluteTopImpressionRate: number | null;\n}\n\nexport interface AdImpressionShareRow {\n adAccountId: string;\n campaignId: string;\n name: string;\n status: string;\n bidStrategy: string;\n segment: string;\n currency: string;\n spend: number;\n impressions: number;\n results: number;\n now: AdSearchShare;\n /** The period before, on settled days; null when nothing compares. */\n before: AdSearchShare | null;\n /** Percentage points, now minus before. */\n points: AdSearchShare | null;\n /** Bidding for a share of impressions: here the share is the goal itself, not a symptom. */\n sharePrimary: boolean;\n /** What holds it back, when one reason dominates: budget, or ad rank (bids and quality). */\n limitedBy: \"budget\" | \"rank\" | null;\n}\n\nexport interface AdPerformanceImpressionShareData {\n window: AdReportWindow;\n comparison: { current: AdDayWindow; previous: AdDayWindow } | null;\n campaigns: AdImpressionShareRow[];\n /** The first day top-of-page rates were measured in this window; null when none was. */\n topMeasuredFrom: string | null;\n matureThrough: AdMatureThrough[];\n}\n\n// --- Keyword quality ---\n\nexport const adPerformanceKeywordQualityRequestSchema = z\n .object({\n ...googleScopeFields,\n /** Only keywords scored at or under this. */\n maxQualityScore: z.number().int().min(1).max(10).default(10),\n limit: z.number().int().min(1).max(500).default(100),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceKeywordQualityRequest = z.input<typeof adPerformanceKeywordQualityRequestSchema>;\n\n/** Google's rating of one part of a keyword's quality score. */\nexport type AdQualityRating = \"below_average\" | \"average\" | \"above_average\" | null;\n\nexport interface AdKeywordQualityRow {\n adAccountId: string;\n entityId: string;\n campaignId: string;\n campaignName: string;\n adGroupId: string;\n adGroupName: string;\n /** As Google Ads writes it: `[exact]`, `\"phrase\"`, `broad`. */\n name: string;\n matchType: string;\n status: string;\n /** 1–10; null when Google gives none (too few searches). */\n qualityScore: number | null;\n expectedCtr: AdQualityRating;\n adRelevance: AdQualityRating;\n landingPageExperience: AdQualityRating;\n /** The page it sends people to, and whether Baker builds it. */\n page: { host: string; path: string; baker: boolean } | null;\n currency: string;\n spend: number;\n impressions: number;\n clicks: number;\n results: number;\n}\n\nexport interface AdKeywordQualitySummary {\n currency: string;\n spend: number;\n /** Spend on keywords Google scored. */\n scoredSpend: number;\n /** Quality score weighted by spend; null when nothing was scored. */\n weightedScore: number | null;\n /** Spend on keywords scored 5 or under. */\n lowScoreSpend: number;\n /** Spend on keywords Google rates below average on each part. */\n belowAverage: { expectedCtr: number; adRelevance: number; landingPageExperience: number };\n}\n\n/** A page keywords lead to, with what Google thinks of the experience. */\nexport interface AdKeywordLanding {\n host: string;\n path: string;\n baker: boolean;\n keywords: number;\n currency: string;\n spend: number;\n /** Spend on its keywords whose landing page experience Google rates below average. */\n belowAverageSpend: number;\n}\n\nexport interface AdPerformanceKeywordQualityData {\n window: AdReportWindow;\n summary: AdKeywordQualitySummary[];\n landings: AdKeywordLanding[];\n rows: AdKeywordQualityRow[];\n totalRows: number;\n}\n\n// --- Monthly budgets ---\n\nexport const AD_BUDGET_SEGMENTS = [\"all\", \"brand\", \"competitor\", \"non_brand\"] as const;\nexport type AdBudgetSegment = (typeof AD_BUDGET_SEGMENTS)[number];\n\n/** What a company plans to spend a month: at one ad account or (both null) across all, on all of it or one segment. */\nexport interface AdMonthlyBudget {\n platform: (typeof AD_PERFORMANCE_PLATFORMS)[number] | null;\n adAccountId: string | null;\n segment: AdBudgetSegment;\n amount: number;\n currency: string;\n}\n\nexport const adPerformanceBudgetsRequestSchema = z.object({\n /** `YYYY-MM`; the current month when absent. */\n month: startedMonthSchema.optional(),\n platforms: z.array(z.enum(AD_PERFORMANCE_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n /** Amounts in this currency (ISO code), or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n});\nexport type AdPerformanceBudgetsRequest = z.input<typeof adPerformanceBudgetsRequestSchema>;\n\n/** How a month's spend paces against a budget: within 5 % of the share of the month gone is on pace. */\nexport type AdBudgetPace = \"on_pace\" | \"under\" | \"over\" | \"no_rate\";\n\n/**\n * Where the month is heading, the one rule the dashboard and the agent read:\n * already over; at the last seven days' pace, out of money before the month\n * ends, or short of the budget by more than 5 %; or on track.\n */\nexport type AdBudgetStatus = \"on_track\" | \"will_underspend\" | \"will_run_out\" | \"over_budget\" | \"no_rate\";\n\nexport interface AdBudgetPacingRow {\n budget: AdMonthlyBudget;\n /** \"All accounts\", \"Google · Parcelo · Brand searches\". */\n label: string;\n /** Spent so far this month, in the budget's currency; null when no rate converts it. */\n spent: number | null;\n /** Spent so far ÷ the budget. */\n usedShare: number | null;\n /** The share of the month gone. */\n expectedShare: number;\n /** The budget × the share of the month gone: what an even month would have spent by now. */\n plannedByNow: number;\n pace: AdBudgetPace;\n status: AdBudgetStatus;\n remaining: number | null;\n /** What each day left can spend to land on the budget. */\n dailyNeeded: number | null;\n /** At the last seven days' rate, where the month ends. */\n projected: number | null;\n /** At that rate, the day the budget is used up, when that is before the month ends. */\n runsOutOn: string | null;\n /** `platform|*:account|*:segment`, what `partOf` names. */\n key: string;\n /** The narrowest other budget that holds this one's spend: shown nested under it, for reading only. */\n partOf: string | null;\n depth: number;\n /** What the budgets inside it add up to, in its currency; above `budget.amount`, the parts are planned above the whole. */\n partsTotal: number | null;\n /**\n * Google Search campaigns in the budget's reach whose daily budget ran out\n * this month (Impression share's \"Budget runs out\"); absent when Google is\n * not connected.\n */\n cappedCampaigns?: number;\n /**\n * The screen's currency and the rate into it, when the budget is in another:\n * every amount here stays in the budget's currency, the screen converts.\n */\n shownIn?: { currency: string; rate: number };\n}\n\nexport interface AdPerformanceBudgetsData {\n month: string;\n asOf: string;\n daysInMonth: number;\n daysLeft: number;\n budgets: AdMonthlyBudget[];\n rows: AdBudgetPacingRow[];\n}\n\nexport const adPerformanceBudgetsSetRequestSchema = z.object({\n /** Where the agent stages the change; required, applied at Publish. */\n chatId: z.string().min(1),\n platform: z.enum(AD_PERFORMANCE_PLATFORMS).nullable().default(null),\n adAccountId: z.string().min(1).nullable().default(null),\n segment: z.enum(AD_BUDGET_SEGMENTS).default(\"all\"),\n /** Null clears the budget. */\n amount: z.number().positive().nullable(),\n currency: z\n .string()\n .regex(/^[A-Za-z]{3}$/)\n .transform((value) => value.toUpperCase())\n .optional(),\n});\nexport type AdPerformanceBudgetsSetRequest = z.input<typeof adPerformanceBudgetsSetRequestSchema>;\n\n// --- Segments: names and a person's choices, staged by the agent ---\n\nexport const adPerformanceSegmentsRequestSchema = z.object({});\nexport type AdPerformanceSegmentsRequest = z.input<typeof adPerformanceSegmentsRequestSchema>;\n\nexport interface AdSegmentChoice {\n kind: \"term\" | \"campaign\";\n platform: (typeof AD_PERFORMANCE_PLATFORMS)[number];\n adAccountId: string;\n key: string;\n label: string;\n segment: \"brand\" | \"competitor\" | \"non_brand\" | \"other\";\n setAt: number;\n}\n\nexport interface AdPerformanceSegmentsData {\n brandNames: string[];\n brandNamesDefault: boolean;\n competitorNames: string[];\n followedCompetitors: string[];\n choices: AdSegmentChoice[];\n targets: AdSegmentTarget[];\n}\n\nexport const adPerformanceSegmentsSetRequestSchema = z\n .object({\n chatId: z.string().min(1),\n /** Replace the brand's own names (company, website, products); empty goes back to its name and website. */\n brandNames: z.array(z.string().min(1).max(80)).max(40).optional(),\n /** Replace the competitor names. */\n competitorNames: z.array(z.string().min(1).max(80)).max(40).optional(),\n /** A campaign's or a search term's segment; `segment` null clears a person's choice. */\n choice: z\n .object({\n kind: z.enum([\"term\", \"campaign\"]),\n adAccountId: z.string().default(\"\"),\n key: z.string().min(1).max(300),\n label: z.string().max(300).optional(),\n segment: z.enum([\"brand\", \"competitor\", \"non_brand\", \"other\"]).nullable(),\n })\n .refine((choice) => choice.kind !== \"campaign\" || choice.adAccountId.trim() !== \"\", {\n message: \"name the campaign's Google Ads account: a campaign id is only unique within its account\",\n path: [\"adAccountId\"],\n })\n .optional(),\n /** A segment's target; `value` null clears it. */\n target: z\n .object({\n segment: z.enum([\"brand\", \"competitor\", \"non_brand\"]),\n metric: z.enum([\"cost_per_result\", \"roas\"]),\n value: z.number().positive().nullable(),\n currency: z\n .string()\n .regex(/^[A-Za-z]{3}$/)\n .transform((value) => value.toUpperCase())\n .optional(),\n })\n .optional(),\n })\n .refine((req) => req.brandNames || req.competitorNames || req.choice || req.target, {\n message: \"name what to change: --brand, --competitors, a --campaign or --term choice, or a --target\",\n });\nexport type AdPerformanceSegmentsSetRequest = z.input<typeof adPerformanceSegmentsSetRequestSchema>;\n\n// --- The Google report: every section in one read ---\n\nexport const adPerformanceGoogleReportRequestSchema = z\n .object({ ...googleScopeFields, months: z.number().int().min(1).max(13).default(6) })\n .superRefine(scopeRules);\nexport type AdPerformanceGoogleReportRequest = z.input<typeof adPerformanceGoogleReportRequestSchema>;\n\n/**\n * Every section of a Google Ads review in one read, for the agent writing a\n * weekly or monthly report: the account snapshot against the period before,\n * the monthly budgets, brand against non-brand, spend by campaign type month\n * by month, every campaign with its change, impression share, the ad groups\n * and keywords that brought most results, keyword quality, and what needs\n * attention. Each section is the same answer its own command gives.\n */\nexport interface AdPerformanceGoogleReportData {\n window: AdReportWindow;\n snapshot: AdPlatformScore[];\n budgets: AdPerformanceBudgetsData | null;\n brandSplit: AdPerformanceBrandSplitData;\n /** Spend and results by campaign type (Google's channel type), month by month. */\n byCampaignType: AdTrendPoint[];\n campaigns: AdEntityRow[];\n impressionShare: AdPerformanceImpressionShareData;\n topAdGroups: AdEntityRow[];\n topKeywords: AdEntityRow[];\n keywordQuality: Pick<AdPerformanceKeywordQualityData, \"summary\" | \"landings\">;\n attention: AdAttentionItem[];\n}\n\ntype Envelope<T> = { ok: true; data: T };\nexport type AdPerformanceBrandSplitResponse = Envelope<AdPerformanceBrandSplitData>;\nexport type AdPerformanceImpressionShareResponse = Envelope<AdPerformanceImpressionShareData>;\nexport type AdPerformanceKeywordQualityResponse = Envelope<AdPerformanceKeywordQualityData>;\nexport type AdPerformanceBudgetsResponse = Envelope<AdPerformanceBudgetsData>;\nexport type AdPerformanceSegmentsResponse = Envelope<AdPerformanceSegmentsData>;\nexport type AdPerformanceGoogleReportResponse = Envelope<AdPerformanceGoogleReportData>;\n","/**\n * `baker ads performance setup` — the Setup checklist for the agent: one\n * sentence on whether everything is set up, what to fix in order, and per ad\n * account and platform the checks behind it — the same checks the dashboard's\n * Setup shows (`convex/adPerformance/setupChecks.ts`).\n */\n\nimport { z } from \"zod\";\nimport { AD_PERFORMANCE_PLATFORMS, idList } from \"./wire\";\n\nexport const adPerformanceSetupRequestSchema = z.object({\n platforms: z.array(z.enum(AD_PERFORMANCE_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n});\nexport type AdPerformanceSetupRequest = z.input<typeof adPerformanceSetupRequestSchema>;\n\nexport type AdSetupState = \"ok\" | \"problem\" | \"waiting\" | \"quiet\";\n\nexport interface AdPerformanceSetupData {\n tone: \"ok\" | \"waiting\" | \"problem\";\n /** One sentence to tell the person as is. */\n headline: string;\n /** In the order to do them. */\n toFix: Array<{ where: string; what: string; fix: string }>;\n /** Per ad account: connected, numbers synced, conversions counted over 30 days. */\n accounts: Array<{\n platform: string;\n adAccountId: string;\n name: string;\n connected: { state: AdSetupState; label: string };\n synced: { state: AdSetupState; label: string };\n conversions: { state: AdSetupState; label: string };\n note: string | null;\n }>;\n /** Per platform that sent visits: whether a visit names its ad. */\n tracking: Array<{ platform: string; state: AdSetupState; label: string }>;\n}\n","/**\n * Wire contract for a Company's ad targets and what they drive: what its ad\n * groups optimise for (`targets`), and per campaign or ad group whether to\n * scale, hold or cut its budget against the target (`budget-recommendations`).\n * Read from Baker's own store (`convex/adPerformance/targets.ts`,\n * `targetReports.ts`); nothing here calls or changes an ad platform.\n *\n * Money targets are stored in the currency they were set in and converted\n * (ECB rates) to compare with numbers in another currency.\n */\n\nimport { z } from \"zod\";\nimport { calendarDaySchema } from \"../calendarDays\";\nimport { adReportCurrencySchema } from \"./currency\";\nimport { type AdResultName, RESULT_NAME_MAX_LENGTH } from \"./resultNoun\";\nimport type { AdSegmentTarget } from \"./search\";\nimport { scopeRules } from \"./wire\";\n\n/** Kept apart from `./index` on purpose: that module re-exports this one, so it cannot be imported back at runtime. */\nconst TARGET_PLATFORMS = [\"meta\", \"google\", \"linkedin\", \"x\", \"chatgpt\"] as const;\ntype TargetPlatform = (typeof TARGET_PLATFORMS)[number];\n\n/** What a target judges: the cost of one result, or the result value each unit of spend brings back. */\nexport const AD_TARGET_FOCUSES = [\"cost_per_result\", \"roas\"] as const;\nexport type AdTargetFocus = (typeof AD_TARGET_FOCUSES)[number];\n\n/** What to do with a campaign's or ad group's budget. */\nexport const AD_BUDGET_MOVES = [\"scale\", \"hold\", \"cut\", \"pause\"] as const;\nexport type AdBudgetMove = (typeof AD_BUDGET_MOVES)[number];\n\n/** A target value: money in `currency` for cost per result, a ratio (`3` = 3×) for return on ad spend. */\nexport interface AdTargetValue {\n value: number;\n currency: string | null;\n}\n\nexport interface AdPlatformTarget extends AdTargetValue {\n platform: TargetPlatform;\n}\n\n/**\n * One target at an ad account (account = platform + ad account id): for one\n * event the account's ads optimise for or count (`event`, a conversion action\n * key as `conversions_by_action` stores it), or — `event` null — for the\n * account's result as a whole. Each target says what it judges (`metric`).\n */\nexport interface AdGoalTarget extends AdPlatformTarget {\n adAccountId: string;\n event: string | null;\n metric: AdTargetFocus;\n}\n\n/**\n * Where a target came from, most specific first: a Search campaign's keyword\n * class (brand, competitor, non-brand — Goals → Search split), the event's at\n * its account, the account's, its platform's (older), or the company default.\n */\nexport type AdTargetSource = \"segment\" | \"event\" | \"account\" | \"platform\" | \"company\";\n\n/** A Google Search campaign's keyword class that can carry a target of its own. */\nexport type AdTargetSegment = AdSegmentTarget[\"segment\"];\n\n/** The target a judgement used, in the judged numbers' currency, and where it is set. */\nexport interface AdJudgingTarget {\n /** A ratio for return on ad spend. */\n value: number;\n currency: string | null;\n metric: AdTargetFocus;\n source: AdTargetSource;\n /** The keyword class whose target it is, when `source` is `segment`. */\n segment: AdTargetSegment | null;\n}\n\n/** Platforms whose stored ad groups say which conversion action they optimise for, so spend splits by event. */\nexport const AD_EVENT_SPLIT_PLATFORMS = [\"meta\", \"linkedin\"] as const;\n\nexport interface AdAlertThresholdValues {\n /** Alert when cost per result rises this many percent over the weeks before. */\n costPerResultRisePct: number;\n /** Alert when a day's spend passes this percent of its daily budget and of its usual spend. */\n overspendPct: number;\n}\n\nexport interface AdPerformanceTargets {\n /** What the company default judges. */\n focus: AdTargetFocus;\n /** The Company's default target; null when none is set. */\n target: AdTargetValue | null;\n /** A platform's own target (set before targets moved to accounts), which wins over the Company's for that platform. */\n platformTargets: AdPlatformTarget[];\n /** Per ad account and event: an event's wins over its account's, which wins over its platform's and the Company's. */\n goalTargets: AdGoalTarget[];\n /** Per keyword class of Google Search campaigns (Goals → Search split): wins over every other for those campaigns. */\n segmentTargets: AdSegmentTarget[];\n alerts: AdAlertThresholdValues;\n /** Today's values for everyone: what `alerts` equals when nothing is set. */\n alertDefaults: AdAlertThresholdValues;\n /** What the company calls one result (\"demo request\"), for every account; null → named from its goals (`resultNoun`). */\n resultName: AdResultName | null;\n updatedAt: number | null;\n}\n\n/** One thing a platform's live ad groups optimise for, and how many do. */\nexport interface AdOptimisationGroup {\n key: string;\n label: string;\n /** False for reach, clicks, views and engagement: not after a conversion. */\n conversion: boolean;\n entities: number;\n /** Their spend over the window, per currency. */\n spend: Array<{ currency: string; amount: number }>;\n /** The conversion actions in Baker's store that count it; null when the store cannot tie it to one. */\n actions: string[] | null;\n /** Whether the Company's result counts what it optimises for; null when that cannot be told. */\n countedByGoal: boolean | null;\n}\n\nexport interface AdPlatformFocus {\n platform: TargetPlatform;\n /** The level that holds what delivery optimises for on this platform. */\n level: \"campaign\" | \"ad_group\";\n groups: AdOptimisationGroup[];\n /** The Company's result on this platform today; empty = the platform's own conversions. */\n goalActions: string[];\n /** A result to choose, from what the ad groups optimise for; only when none is chosen. Never applied by itself. */\n suggestion: { actions: string[]; labels: string[]; why: string } | null;\n /** The result counts other actions than the ones delivery optimises for. */\n mismatch: { message: string; spendShare: number } | null;\n /** What Baker can and cannot tell on this platform. */\n note: string | null;\n}\n\n/** One ad account's share of its platform's focus: what its own live ads optimise for. */\nexport interface AdAccountFocus {\n platform: TargetPlatform;\n adAccountId: string;\n groups: AdOptimisationGroup[];\n /** The platform's result counts other actions than the ones this account's delivery optimises for. */\n mismatch: { message: string; spendShare: number } | null;\n}\n\nexport interface AdPerformanceFocusData {\n window: { from: string; to: string; days: number };\n platforms: AdPlatformFocus[];\n /** The same, per ad account: each account optimises for its own events. */\n accounts: AdAccountFocus[];\n}\n\nexport interface AdPerformanceTargetsData {\n targets: AdPerformanceTargets;\n /** The currencies of the Company's selected ad accounts: the ones a money target can be in. */\n currencies: string[];\n focus: AdPerformanceFocusData;\n /** Per ad account and event: the period's numbers against the target that judges them. */\n goals: AdGoalsData;\n /** What this chat staged on top, applied when it is published. */\n staged: AdGoalStagedOp[];\n}\n\n/** Where a number stands against its target. */\nexport type AdGoalStatus = \"on_target\" | \"above_target\" | \"below_target\" | \"no_target\" | \"no_rate\" | \"not_enough_data\";\n\n/** The target that judges a row, in the row's currency. */\nexport interface AdResolvedGoalTarget {\n /** In `currency`; a ratio for return on ad spend. Null: set, but no exchange rate compares it. */\n value: number | null;\n currency: string | null;\n metric: AdTargetFocus;\n source: AdTargetSource;\n /** The keyword class whose target it is, when `source` is `segment`. */\n segment?: AdTargetSegment;\n /** As it was set, in the currency it was set in. */\n set: AdTargetValue;\n}\n\nexport interface AdGoalNumbers {\n /** Null where the platform cannot split spend by event: say so, judge the account instead. */\n spend: number | null;\n results: number;\n value: number;\n costPerResult: number | null;\n roas: number | null;\n target: AdResolvedGoalTarget | null;\n status: AdGoalStatus;\n}\n\n/** One event an ad account's ads optimise for or count, with its own numbers. */\nexport interface AdGoalEventRow extends AdGoalNumbers {\n /** The conversion action key, as `conversions_by_action` stores it: what a target and a result name. */\n event: string;\n /** Every action key the row folds together (a family the platform reports apart); `[event]` when it is one. */\n actions: string[];\n label: string;\n /** Whether it counts as a result in this account: any of its actions counted. */\n counted: boolean;\n /** Live ad groups (or campaigns) optimising for it over the period, and the campaigns they belong to. */\n optimisedBy: { entities: number; campaigns: number } | null;\n}\n\n/** A kind of search judged by its own target. `value` null: set, but no rate compares it. */\nexport interface AdSearchSplitVerdict {\n segment: AdTargetSegment;\n value: number | null;\n currency: string | null;\n metric: AdTargetFocus;\n /** The period's cost per result, or return, for this kind of search. */\n actual: number | null;\n status: AdGoalStatus;\n}\n\nexport interface AdGoalAccountRow {\n platform: TargetPlatform;\n adAccountId: string;\n name: string;\n /** The account's own currency. */\n accountCurrency: string;\n /** What the amounts are in: the report currency, or the account's own. */\n currency: string;\n /** The platform says which event each ad group optimises for, so spend splits by event. */\n split: boolean;\n /** What Baker cannot tell on this platform, in plain words. */\n note: string | null;\n /** What counts as a result here, and whether it is this account's own choice or the platform's. */\n results: { actions: string[]; source: \"account\" | \"platform\" | \"platform_conversions\" };\n events: AdGoalEventRow[];\n /** The account's whole result, judged against the account's target. */\n total: AdGoalNumbers;\n /**\n * A Google account whose Search targets are split (Goals → Search split):\n * each kind of search's verdict. These judge the account — on the Summary\n * too — rather than `total`'s. Empty otherwise.\n */\n searchSplit: AdSearchSplitVerdict[];\n /** The result counts other actions than the ones delivery optimises for. */\n mismatch: string | null;\n /** Other actions the account reported over the period, offered to count. */\n available: Array<{ event: string; label: string; results: number }>;\n}\n\nexport interface AdGoalsData {\n window: { from: string; to: string; days: number };\n /** An ISO code, or '' when amounts are in each account's own currency. */\n currency: string;\n accounts: AdGoalAccountRow[];\n}\n\n/** One goal or target a chat staged, as the review and the agent read it. */\nexport interface AdGoalStagedOp {\n /**\n * `target:<platform>:<account>:<event>`, `target:company`, `results:<platform>:<account>`,\n * `segments:names`, `segments:<term|campaign>:<platform>:<account>:<key>`, `segments:target:<segment>`,\n * `budget:<platform|*>:<account|*>:<segment>`, `result_name`, `alert:<id>`, `alert_line:<line>`,\n * `library:<platform>:<creativeKey>`, or `reporting_currency`.\n */\n key: string;\n kind:\n | \"target\"\n | \"results\"\n | \"segment_names\"\n | \"segment_choice\"\n | \"segment_target\"\n | \"budget\"\n | \"result_name\"\n | \"alert\"\n | \"alert_line\"\n | \"library_link\"\n | \"reporting_currency\";\n /** What it is about: \"Company default\", or the platform, account and event. */\n label: string;\n before: string;\n after: string;\n /** Whether it sets something new, changes what is there, or takes it away. */\n change?: \"added\" | \"changed\" | \"removed\";\n /** The ad platform it is about, for its mark; absent for company-wide goals. */\n platform?: TargetPlatform;\n stagedAt: number;\n result?: { status: \"applied\" | \"skipped\"; reason?: string };\n /** In a stage's answer only: it changes nothing (already the value), so nothing was staged for it. */\n noChange?: boolean;\n /** With `noChange`: what this chat had staged for the same thing was taken back. */\n unstaged?: boolean;\n}\n\nexport interface AdBudgetWindowNumbers {\n from: string;\n to: string;\n spend: number;\n results: number;\n resultValue: number;\n /** Cost per result, or return on ad spend, by the focus; null with no results or no spend. */\n metric: number | null;\n}\n\nexport interface AdBudgetRecommendation {\n platform: TargetPlatform;\n adAccountId: string;\n level: \"campaign\" | \"ad_group\";\n entityId: string;\n name: string;\n campaignId: string;\n campaignName: string;\n currency: string;\n /** The ad account's own currency, the one its budgets are set in; absent when unknown. */\n accountCurrency?: string;\n move: AdBudgetMove;\n /** One line: why, in numbers. */\n reason: string;\n /** The reason without its numbers, one short sentence: \"It lost 25% of its search impressions to its budget: more budget buys more.\" */\n why: string;\n /** How sure: `strong` | `moderate` for scale and cut; `weak` for the rest. */\n confidence: \"strong\" | \"moderate\" | \"weak\";\n /** What it is judged on: the target's own metric. */\n metric: AdTargetFocus;\n last7: AdBudgetWindowNumbers;\n last3: AdBudgetWindowNumbers;\n target: number;\n /** Which target that is (`resolveGoalTarget`): its keyword class's, its event's, its account's, or the default. */\n targetSource: AdTargetSource;\n /** The keyword class whose target judged it, when `targetSource` is `segment`. */\n targetSegment: AdTargetSegment | null;\n /** The ad account's spend-weighted average at the same level, same windows. */\n accountAverage: number | null;\n /** A scale or cut held back by a recent edit: the first day it may move, `YYYY-MM-DD` (the entity panel's \"Wait until\"). */\n waitUntil?: string;\n budget: {\n daily: number | null;\n suggestedDaily: number | null;\n changePct: number | null;\n /** Days to wait after this step before the next one. */\n waitDays: number;\n };\n /**\n * The alert this move is stored as in What needs attention, while it is\n * open: what Handle with agent, a claim and Resolve name. Absent for a hold,\n * or a move a person dismissed.\n */\n alert?: { id: string; claimedByChatId: string | null; fixing: boolean };\n}\n\nexport interface AdPerformanceBudgetRecommendationsData {\n focus: AdTargetFocus;\n hasTarget: boolean;\n rows: AdBudgetRecommendation[];\n counts: Record<AdBudgetMove, number>;\n /** Campaigns with live spend that no target judges (none set, or no exchange rate compares it), per currency. */\n untargeted: Array<{ currency: string; entities: number }>;\n matureThrough: Array<{ platform: TargetPlatform; date: string; lagDays: number }>;\n}\n\nconst idList = z\n .array(\n z\n .string()\n .min(1)\n .regex(/^[^,]+$/, \"ids cannot contain commas\"),\n )\n .max(200);\n\n/**\n * `days` from 1, like a start/end, which was always read at any length: the\n * per-event table judges whatever period it is given (`goalsReport`), and a\n * 7-day floor on one spelling only refused what the other took.\n */\nexport const adPerformanceTargetsRequestSchema = z\n .object({\n platforms: z.array(z.enum(TARGET_PLATFORMS)).optional(),\n /** The period the per-event numbers cover; 30 days when absent. */\n days: z.number().int().min(1).max(400).optional(),\n start: calendarDaySchema.optional(),\n end: calendarDaySchema.optional(),\n currency: adReportCurrencySchema.optional(),\n /** Show what this chat staged on top. */\n chatId: z.string().min(1).optional(),\n })\n .superRefine(scopeRules);\nexport type AdPerformanceTargetsRequest = z.input<typeof adPerformanceTargetsRequestSchema>;\n\nexport const adPerformanceBudgetRecommendationsRequestSchema = z.object({\n platforms: z.array(z.enum(TARGET_PLATFORMS)).optional(),\n adAccountIds: idList.optional(),\n /** Money in this currency (ISO code), or `native` for each account's own; absent → the company's reporting currency. */\n currency: adReportCurrencySchema.optional(),\n /** Only these moves; all when absent. */\n moves: z.array(z.enum(AD_BUDGET_MOVES)).optional(),\n limit: z.number().int().min(1).max(200).default(50),\n});\nexport type AdPerformanceBudgetRecommendationsRequest = z.input<typeof adPerformanceBudgetRecommendationsRequestSchema>;\n\nconst currencyCode = z\n .string()\n .regex(/^[A-Za-z]{3}$/, \"use a currency code like EUR\")\n .transform((value) => value.toUpperCase());\n\n/**\n * `baker ads performance targets set`: stage one target on the chat — the\n * company default, an ad account's whole result, or one event at an account.\n * `value: null` clears it. Applied when the chat is published.\n */\nexport const adTargetStageRequestSchema = z\n .object({\n chatId: z.string().min(1),\n company: z.boolean().optional(),\n platform: z.enum(TARGET_PLATFORMS).optional(),\n adAccountId: z.string().min(1).max(100).optional(),\n event: z.string().trim().min(1).max(300).optional(),\n metric: z.enum(AD_TARGET_FOCUSES).optional(),\n value: z.number().positive().max(1e9).nullable(),\n currency: currencyCode.optional(),\n })\n .superRefine((body, ctx) => {\n const account = body.platform !== undefined || body.adAccountId !== undefined;\n if (body.company === true && (account || body.event !== undefined))\n ctx.addIssue({ code: \"custom\", message: \"A company default names no platform, ad account or event.\" });\n if (body.company !== true && (body.platform === undefined || body.adAccountId === undefined))\n ctx.addIssue({\n code: \"custom\",\n message: \"Name the ad account (platform and account id), or the company default.\",\n });\n if (body.value !== null && body.metric === undefined)\n ctx.addIssue({ code: \"custom\", message: \"Say what the target judges: cost per result or return on ad spend.\" });\n if (body.value !== null && body.metric === \"cost_per_result\" && body.currency === undefined)\n ctx.addIssue({ code: \"custom\", message: \"A cost per result target needs its currency.\" });\n });\nexport type AdTargetStageRequest = z.input<typeof adTargetStageRequestSchema>;\n\n/** `baker ads performance goals set`: stage what counts as a result at one ad account. */\nexport const adResultsStageRequestSchema = z\n .object({\n chatId: z.string().min(1),\n platform: z.enum(TARGET_PLATFORMS),\n adAccountId: z.string().min(1).max(100),\n /** Conversion action keys to start counting. */\n count: z.array(z.string().trim().min(1).max(300)).max(50).default([]),\n /** Conversion action keys to stop counting. */\n uncount: z.array(z.string().trim().min(1).max(300)).max(50).default([]),\n /** `--count` as written, one string: staged whole when it is one action the account has (\"Leads, all\"). */\n countText: z.string().trim().min(1).max(15000).optional(),\n uncountText: z.string().trim().min(1).max(15000).optional(),\n /** Back to what the platform counts for every account (its own choice gone). */\n reset: z.boolean().optional(),\n })\n .refine((body) => body.reset === true || body.count.length + body.uncount.length > 0, {\n message: \"Name actions to count or stop counting, or reset.\",\n })\n .refine((body) => body.reset !== true || body.count.length + body.uncount.length === 0, {\n message: \"A reset drops the account's own choice: pass it alone, not with actions to count or stop counting.\",\n path: [\"reset\"],\n });\nexport type AdResultsStageRequest = z.input<typeof adResultsStageRequestSchema>;\n\nconst resultWord = z.string().trim().min(1).max(RESULT_NAME_MAX_LENGTH);\n\n/**\n * `baker ads performance goals name`: stage what the company calls one result\n * (\"demo request\" / \"demo requests\"), or `reset` to name it from the goals again.\n */\nexport const adResultNameStageRequestSchema = z\n .object({\n chatId: z.string().min(1),\n singular: resultWord.optional(),\n plural: resultWord.optional(),\n reset: z.boolean().optional(),\n })\n .refine((body) => (body.reset === true) !== (body.singular !== undefined && body.plural !== undefined), {\n message: \"Name one result and several (--singular lead --plural leads), or reset.\",\n });\nexport type AdResultNameStageRequest = z.input<typeof adResultNameStageRequestSchema>;\n\n/** The two alert lines a company may set, as `AdAlertThresholdValues` names them. */\nexport const AD_ALERT_LINES = [\"costPerResultRisePct\", \"overspendPct\"] as const;\nexport type AdAlertLine = (typeof AD_ALERT_LINES)[number];\n\n/**\n * `baker ads performance targets alert-lines`: stage one or both alert lines,\n * in percent; `null` puts a line back to Baker's default. Applied when the\n * chat is published.\n */\nexport const adAlertLinesStageRequestSchema = z\n .object({\n chatId: z.string().min(1),\n costPerResultRisePct: z.number().int().min(10).max(300).nullable().optional(),\n overspendPct: z.number().int().min(110).max(500).nullable().optional(),\n })\n .refine((body) => body.costPerResultRisePct !== undefined || body.overspendPct !== undefined, {\n message: \"Name a line to change: the cost per result rise (10-300) or the overspend (110-500), or default.\",\n });\nexport type AdAlertLinesStageRequest = z.input<typeof adAlertLinesStageRequestSchema>;\n\n/** `baker ads performance targets unstage`: take back one staged goal or target, or all of them. */\nexport const adGoalUnstageRequestSchema = z\n .object({ chatId: z.string().min(1), key: z.string().min(1).optional(), all: z.boolean().optional() })\n .refine((body) => (body.key === undefined) !== (body.all !== true), {\n message: \"Pass one staged key or all.\",\n });\nexport type AdGoalUnstageRequest = z.input<typeof adGoalUnstageRequestSchema>;\n\ntype Envelope<T> = { ok: true; data: T };\nexport type AdGoalStageResponse = Envelope<{ staged: AdGoalStagedOp[] }> & { hints?: string[] };\nexport type AdGoalUnstageResponse = Envelope<{ removed: number }> & { hints?: string[] };\nexport type AdPerformanceTargetsResponse = Envelope<AdPerformanceTargetsData>;\nexport type AdPerformanceBudgetRecommendationsResponse = Envelope<AdPerformanceBudgetRecommendationsData>;\n","/**\n * What one result is called — \"lead\", \"sign-up\", \"demo request\" — the same\n * on every Ads screen, the Measure overview and in `baker ads performance`.\n *\n * A company may name it itself (`resultName` on its targets row, set in\n * Goals → Company default or staged by the agent): that is its choice for\n * every account, so it always wins. Unnamed, the noun is read from what the\n * goals count — \"Leads\" when every goal action is a lead — but only while\n * every account in view has a goal: an account with none counts each\n * platform's own conversions, and \"Leads\" over that count is a claim the\n * number does not support, so it says \"Results\". With no goal anywhere it\n * says \"Conversions\", what the platforms count by default.\n */\n\n/** A company's own name for one result, singular and plural as it writes them. */\nexport interface AdResultName {\n singular: string;\n plural: string;\n}\n\n/** The resolved noun: `heading` for a column or tile, `singular`/`plural` inside a sentence. */\nexport interface AdResultNoun {\n heading: string;\n singular: string;\n plural: string;\n /** `company` its own name; `goal` read from its goals; `mixed` goals that disagree or leave an account out; `platform` no goal. */\n source: \"company\" | \"goal\" | \"mixed\" | \"platform\";\n}\n\n/** Long enough for \"qualified demo request\", short enough for a column heading. */\nexport const RESULT_NAME_MAX_LENGTH = 40;\n\n/**\n * Which kind of result a goal action counts, by the words platforms use for it.\n * Ordered: \"lead form submit\" is a lead, not a submission of something else.\n */\nconst RESULT_KINDS: ReadonlyArray<{ pattern: RegExp; singular: string; plural: string }> = [\n { pattern: /lead/i, singular: \"lead\", plural: \"leads\" },\n { pattern: /purchase|checkout|order/i, singular: \"purchase\", plural: \"purchases\" },\n { pattern: /sign_?up|registration|register/i, singular: \"sign-up\", plural: \"sign-ups\" },\n { pattern: /contact|call/i, singular: \"contact\", plural: \"contacts\" },\n { pattern: /subscri/i, singular: \"subscription\", plural: \"subscriptions\" },\n { pattern: /install/i, singular: \"install\", plural: \"installs\" },\n];\n\nconst RESULTS = { singular: \"result\", plural: \"results\" };\nconst CONVERSIONS = { singular: \"conversion\", plural: \"conversions\" };\n\nfunction capitalised(word: string): string {\n return word.charAt(0).toUpperCase() + word.slice(1);\n}\n\n/** \"Booking\" reads \"booking\" inside a sentence; \"MQL\" stays \"MQL\". */\nfunction inSentence(word: string): string {\n const second = word.charAt(1);\n return second !== \"\" && second === second.toLowerCase() && second !== second.toUpperCase()\n ? word.charAt(0).toLowerCase() + word.slice(1)\n : word;\n}\n\nfunction noun(words: AdResultName, source: AdResultNoun[\"source\"]): AdResultNoun {\n const singular = inSentence(words.singular);\n const plural = inSentence(words.plural);\n return { heading: capitalised(plural), singular, plural, source };\n}\n\ninterface GoalLike {\n platform: string;\n adAccountId?: string;\n actions: readonly string[];\n}\n\nfunction covered(goals: readonly GoalLike[], account: { platform: string; adAccountId: string }): boolean {\n return goals.some(\n (goal) =>\n goal.platform === account.platform &&\n goal.actions.length > 0 &&\n (goal.adAccountId === undefined || goal.adAccountId === account.adAccountId),\n );\n}\n\n/**\n * The noun for results over these goals and the ad accounts in view. Without\n * `accounts` (not known yet) it judges the goals alone.\n */\nexport function resultNoun(input: {\n name: AdResultName | null | undefined;\n goals: readonly GoalLike[];\n accounts?: ReadonlyArray<{ platform: string; adAccountId: string }>;\n}): AdResultNoun {\n if (input.name) return noun(input.name, \"company\");\n const actions = input.goals.flatMap((goal) => goal.actions);\n if (actions.length === 0) return noun(CONVERSIONS, \"platform\");\n if (input.accounts?.some((account) => !covered(input.goals, account))) return noun(RESULTS, \"mixed\");\n const kinds = new Set(actions.map((action) => RESULT_KINDS.find((kind) => kind.pattern.test(action))));\n const [only] = kinds;\n return kinds.size === 1 && only ? noun(only, \"goal\") : noun(RESULTS, \"mixed\");\n}\n\n/** Several of a singular by the regular English rule: \"lead\" → \"leads\", \"enquiry\" → \"enquiries\", \"match\" → \"matches\". */\nexport function pluralOf(singular: string): string {\n if (/[^aeiou]y$/i.test(singular)) return `${singular.slice(0, -1)}ies`;\n if (/(s|sh|ch|x|z)$/i.test(singular)) return `${singular}es`;\n return `${singular}s`;\n}\n\n/** Spaces trimmed and collapsed, as it is stored. */\nexport function cleanResultName(name: AdResultName): AdResultName {\n const clean = (word: string) => word.trim().replace(/\\s+/g, \" \");\n return { singular: clean(name.singular), plural: clean(name.plural) };\n}\n\n/** Why this name cannot be saved, or null. Expects a cleaned name. */\nexport function resultNameProblem(name: AdResultName): string | null {\n if (name.singular === \"\" || name.plural === \"\") return \"Write both words: one result and several (lead, leads).\";\n if (name.singular.length > RESULT_NAME_MAX_LENGTH || name.plural.length > RESULT_NAME_MAX_LENGTH)\n return `Keep each word under ${RESULT_NAME_MAX_LENGTH} characters.`;\n return null;\n}\n","import {\n type AdDataStatus,\n type AdPerformanceBreakdownData,\n type AdPerformanceChangesData,\n type AdPerformanceCreativesData,\n type AdPerformanceDiagnosisData,\n type AdPerformanceEntitiesData,\n type AdPerformanceEntityData,\n type AdPerformanceFunnelData,\n type AdPerformanceGoalsData,\n type AdPerformanceImpactData,\n type AdPerformanceLandingsData,\n type AdPerformanceOverviewData,\n type AdPerformancePacingData,\n type AdPerformanceProgressData,\n type AdPerformancePulseData,\n type AdPerformanceSearchTermsData,\n type AdPerformanceTrackingData,\n adPerformanceBreakdownRequestSchema,\n adPerformanceChangesRequestSchema,\n adPerformanceCreativesRequestSchema,\n adPerformanceDiagnosisRequestSchema,\n adPerformanceEntitiesRequestSchema,\n adPerformanceEntityRequestSchema,\n adPerformanceFunnelRequestSchema,\n adPerformanceGoalsRequestSchema,\n adPerformanceImpactRequestSchema,\n adPerformanceLandingsRequestSchema,\n adPerformanceOverviewRequestSchema,\n adPerformancePacingRequestSchema,\n adPerformanceProgressRequestSchema,\n adPerformancePulseRequestSchema,\n adPerformanceSearchTermsRequestSchema,\n adPerformanceTrackingRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { defineCommand } from \"citty\";\nimport { z } from \"zod\";\nimport { accountsCommand } from \"./accounts.ts\";\nimport {\n BREAKDOWN_ARGS,\n breakdownInput,\n CHANGES_ARGS,\n CREATIVES_ARGS,\n changesInput,\n creativesInput,\n ENTITIES_ARGS,\n ENTITY_ARGS,\n entitiesInput,\n entityInput,\n FUNNEL_ARGS,\n funnelInput,\n GOALS_ARGS,\n goalsInput,\n IMPACT_ARGS,\n impactInput,\n PACING_ARGS,\n pacingInput,\n SCOPE_ARGS,\n SEARCH_TERMS_ARGS,\n STATUS_ARGS,\n scopeInput,\n searchTermsInput,\n TRACKING_ARGS,\n} from \"./args.ts\";\nimport { attentionCommand } from \"./attention.ts\";\nimport { creativeAssetsCommand } from \"./creativeAssets.ts\";\nimport { creativeHealthCommand } from \"./creativeHealth.ts\";\nimport { currencyCommand } from \"./currency.ts\";\nimport { anomaliesCommand, recapCommand } from \"./diagnostic.ts\";\nimport {\n goalsNameCommand,\n goalsSetCommand,\n targetsAlertLinesCommand,\n targetsSetCommand,\n targetsUnstageCommand,\n withWrites,\n} from \"./goalWrites.ts\";\nimport { healthCommand } from \"./health.ts\";\nimport { familiesCommand } from \"./library.ts\";\nimport { liveInCommand } from \"./liveIn.ts\";\nimport { ladderCommand, peopleOutcomesCommand, personaFieldsCommand, personasCommand } from \"./people.ts\";\nimport {\n compactDiagnosis,\n compactProgress,\n compactPulse,\n DIAGNOSE_ARGS,\n diagnoseInput,\n diagnosisHints,\n PROGRESS_ARGS,\n PULSE_ARGS,\n progressHints,\n progressInput,\n pulseHints,\n pulseInput,\n} from \"./progress.ts\";\nimport {\n breakdownHints,\n changesHints,\n clippedWindowHint,\n compactBreakdown,\n compactChanges,\n compactCreatives,\n compactEntities,\n compactEntity,\n compactImpact,\n compactOverview,\n compactStatus,\n creativesHints,\n entitiesHints,\n entityHints,\n funnelHints,\n goalsHints,\n impactHints,\n overviewHints,\n statusHints,\n trackingHints,\n} from \"./report.ts\";\nimport { report, STORE_NOTE } from \"./reportCommand.ts\";\nimport { compactSearchTerms, searchCommands, searchTermsHints } from \"./search.ts\";\nimport { setupCommand } from \"./setup.ts\";\nimport { budgetRecommendationsCommand, targetsCommand } from \"./targets.ts\";\nimport { trendCommand } from \"./trend.ts\";\n\n/**\n * `baker ads performance` — the agent's read of Baker's stored copy of every\n * connected ad platform. Nothing here calls a platform and nothing changes\n * anywhere; the live `baker ads <platform>` commands stay for what the store\n * lacks and for staged writes.\n */\n\nconst overviewCommand = report<typeof adPerformanceOverviewRequestSchema, AdPerformanceOverviewData>({\n name: \"overview\",\n schemaName: \"overview\",\n schemaDescription: `Start here for any ad performance question. Every connected platform's score for the window (spend, results, cost per result, against the settled days before), totals per currency, a trend, matureThrough per platform (the last day whose results have settled), the result goals in force, open alerts and data status. Default the last 30 complete days. ${STORE_NOTE}`,\n help: \"Every ad platform's results at a glance. Example: baker ads performance overview --days 30\",\n path: \"overview\",\n args: SCOPE_ARGS,\n request: adPerformanceOverviewRequestSchema,\n input: scopeInput,\n compact: compactOverview,\n hints: overviewHints,\n});\n\nconst entitiesCommand = report<typeof adPerformanceEntitiesRequestSchema, AdPerformanceEntitiesData>({\n name: \"entities\",\n schemaName: \"entities\",\n schemaDescription: `Campaigns, ad groups / ad sets, ads or keywords across platforms, ranked (default by spend), with metrics, budget, first delivery (beforeHistory: it ran before the stored history starts) and peer shares against its parent. Paged with --limit/--offset; totalRows counts every match. ${STORE_NOTE}`,\n help: \"Campaigns, ad groups, ads or keywords ranked. Example: baker ads performance entities --level ad --sort cost_per_result --order asc\",\n path: \"entities\",\n args: ENTITIES_ARGS,\n request: adPerformanceEntitiesRequestSchema,\n input: entitiesInput,\n compact: compactEntities,\n hints: (data, request) => entitiesHints(data, request),\n});\n\nconst entityCommand = report<typeof adPerformanceEntityRequestSchema, AdPerformanceEntityData>({\n name: \"entity\",\n schemaName: \"entity\",\n schemaDescription: `Read this before changing a campaign, ad group, ad or keyword. One entity's numbers, its daily series (mature: settled), its change history, its children and open alerts, and a verdict: enoughData (is there enough settled data to judge it), daysSinceChange, learning, and safeBudgetStep (the largest budget step that keeps learning, and how many days to wait). ${STORE_NOTE}`,\n help: \"One entity before you change it, with a verdict. Example: baker ads performance entity 120211 --platform meta --level campaign\",\n path: \"entity\",\n args: ENTITY_ARGS,\n request: adPerformanceEntityRequestSchema,\n input: entityInput,\n compact: compactEntity,\n hints: entityHints,\n});\n\nconst changesCommand = report<typeof adPerformanceChangesRequestSchema, AdPerformanceChangesData>({\n name: \"changes\",\n schemaName: \"changes\",\n schemaDescription: `What changed in the ad accounts and who changed it: status, budget, bid, schedule, creative, targeting edits, by a person, by the platform's automation, or published from Baker (--actor-kinds baker). A Baker change also seen in the platform's own log or sync is one row, Baker's: chatTitle names the chat it was published from, platformCheck says whether the platform shows it (seen | not_seen). Every other row was made outside Baker. Each row names its adAccountId (and campaignId below a campaign). Amounts in a change's summary stay in the ad account's own currency (valueCurrency), whatever --currency says. Newest first, paged with --limit/--offset; totalRows counts every match. ${STORE_NOTE}`,\n help: \"Changes made to the ad accounts, and by whom. Example: baker ads performance changes --kinds budget,status --days 14\",\n path: \"changes\",\n args: CHANGES_ARGS,\n request: adPerformanceChangesRequestSchema,\n input: changesInput,\n compact: compactChanges,\n hints: changesHints,\n});\n\nconst impactCommand = report<typeof adPerformanceImpactRequestSchema, AdPerformanceImpactData>({\n name: \"impact\",\n schemaName: \"impact\",\n schemaDescription: `Did a change work? Each change's settled days before against the days after (--impact-days, default 7), against what the rest of the ad account did meanwhile. verdict: better | worse | unclear | too_early | stopped (the change removed it: no after period to judge); effect is relative (0.2 = +20%); confounded when another change overlaps. One publish's edits to one setting are one line: edits counts them, editSample names the first few (--full: editValues, all of them). --actor-kinds baker checks the changes Baker published. Newest first, paged with --limit/--offset; totalRows counts every match. ${STORE_NOTE}`,\n help: \"Whether recent changes worked. Example: baker ads performance impact --actor-kinds baker --days 60\",\n path: \"impact\",\n args: IMPACT_ARGS,\n request: adPerformanceImpactRequestSchema,\n input: impactInput,\n compact: compactImpact,\n hints: impactHints,\n});\n\nconst creativesCommand = report<typeof adPerformanceCreativesRequestSchema, AdPerformanceCreativesData>({\n name: \"creatives\",\n schemaName: \"creatives\",\n schemaDescription: `Which creatives win. The same creative across ads counts once (--group-by ad to split); grouping by creative leaves out ads with no picture or video (Google Search text ads): --group-by ad lists them. libraryKey (mediaKey with --full) is the key families choices and families link take. peerIndex compares each with its ad-group siblings and is shrunk toward 1 when data is thin; peerStanding says above_peers | like_peers | below_peers | too_little_data. Rank by it, not by raw cost per result. ${STORE_NOTE}`,\n help: \"Creatives against their siblings. Example: baker ads performance creatives --platforms meta --min-spend 50\",\n path: \"creatives\",\n args: CREATIVES_ARGS,\n request: adPerformanceCreativesRequestSchema,\n input: creativesInput,\n compact: compactCreatives,\n hints: creativesHints,\n});\n\nconst breakdownCommand = report<typeof adPerformanceBreakdownRequestSchema, AdPerformanceBreakdownData>({\n name: \"breakdown\",\n schemaName: \"breakdown\",\n schemaDescription: `Spend and results split by placement, country or device (Meta and Google Ads), with each value's share of spend and of results, cost per result and CTR. Meta only: age, gender, and audience_segment (prospecting | engaged | existing | unclassified — Advantage+ sales campaigns' customer segments; unclassified elsewhere). ${STORE_NOTE}`,\n help: \"Results by placement, country, device, age, gender or audience segment. Example: baker ads performance breakdown --dimension placement\",\n path: \"breakdown\",\n args: BREAKDOWN_ARGS,\n request: adPerformanceBreakdownRequestSchema,\n input: breakdownInput,\n compact: compactBreakdown,\n hints: breakdownHints,\n});\n\nconst searchTermsCommand = report<typeof adPerformanceSearchTermsRequestSchema, AdPerformanceSearchTermsData>({\n name: \"search-terms\",\n schemaName: \"searchTerms\",\n schemaDescription: `Google Ads search terms that triggered the ads, with the keyword they matched, spend, clicks and conversions. --zero-results keeps only terms with no conversions: the negative-keyword candidates. Each row: the term, its match type and keyword, campaign and ad group ids, how Baker read it (termSegment, termUnsure, termChosen: a person chose) against its campaign's segment, spend, clicks, conversions and cost per conversion; --full adds every other field (impressions, CTR, keyword id…). Paged with --limit/--offset; totalRows counts every match. ${STORE_NOTE}`,\n help: \"Google Ads search terms. Example: baker ads performance search-terms --zero-results --min-clicks 5\",\n path: \"search-terms\",\n args: SEARCH_TERMS_ARGS,\n request: adPerformanceSearchTermsRequestSchema,\n input: searchTermsInput,\n compact: compactSearchTerms,\n hints: searchTermsHints,\n});\n\nconst pacingCommand = report<typeof adPerformancePacingRequestSchema, AdPerformancePacingData>({\n name: \"pacing\",\n schemaName: \"pacing\",\n schemaDescription: `Month-to-date spend per ad account, the last 7 days, the active daily budgets, and the spend projected to the month's end. ${STORE_NOTE}`,\n help: \"Month spend so far and where it lands. Example: baker ads performance pacing --month 2026-10\",\n path: \"pacing\",\n args: PACING_ARGS,\n request: adPerformancePacingRequestSchema,\n input: pacingInput,\n});\n\nconst funnelCommand = report<typeof adPerformanceFunnelRequestSchema, AdPerformanceFunnelData>({\n name: \"funnel\",\n schemaName: \"funnel\",\n schemaDescription: `From ad to site: spend and link clicks beside the visits, engaged visits and site conversions they brought, per campaign, ad group or ad (--by-landing splits by the page entered). clickToSession below ~0.6 means clicks are not arriving, or not arriving tagged. ${STORE_NOTE}`,\n help: \"Ad spend to site visits and conversions. Example: baker ads performance funnel --level campaign --by-landing\",\n path: \"funnel\",\n args: FUNNEL_ARGS,\n request: adPerformanceFunnelRequestSchema,\n input: funnelInput,\n hints: funnelHints,\n});\n\nconst trackingCommand = report<typeof adPerformanceTrackingRequestSchema, AdPerformanceTrackingData>({\n name: \"tracking\",\n schemaName: \"tracking\",\n schemaDescription: `Can paid visits be tied back to their ads? Per platform: the share of paid visits carrying a click id, campaign id and ad id, and the active ads that send no tracking parameters (with their last 7 days of spend). ${STORE_NOTE}`,\n help: \"Whether ad clicks arrive tagged. Example: baker ads performance tracking\",\n path: \"tracking\",\n args: TRACKING_ARGS,\n request: adPerformanceTrackingRequestSchema,\n input: scopeInput,\n hints: trackingHints,\n});\n\nconst landingsCommand = report<typeof adPerformanceLandingsRequestSchema, AdPerformanceLandingsData>({\n name: \"landings\",\n schemaName: \"landings\",\n schemaDescription: `Which landing pages the active ads send people to: ads, campaigns and platforms per page, spend per currency, paid visits and their site conversions. ${STORE_NOTE}`,\n help: \"Landing pages the ads point at. Example: baker ads performance landings --days 14\",\n path: \"landings\",\n args: TRACKING_ARGS,\n request: adPerformanceLandingsRequestSchema,\n input: scopeInput,\n hints: clippedWindowHint,\n});\n\nconst goalsCommand = report<typeof adPerformanceGoalsRequestSchema, AdPerformanceGoalsData>({\n name: \"goals\",\n schemaName: \"goals\",\n schemaDescription:\n \"Which conversion actions count as results today (goals, per platform) and every action each platform reported in the last --days (default 90) or --start/--end, for the ad accounts named (--platforms, --ad-account-ids; default every selected one), with inGoal. Read-only.\",\n help: \"Conversion actions and which count as results. Example: baker ads performance goals\",\n path: \"goals\",\n args: GOALS_ARGS,\n request: adPerformanceGoalsRequestSchema,\n input: goalsInput,\n hints: goalsHints,\n});\n\nconst statusRequest = z.object({});\n\nconst statusCommand = report<typeof statusRequest, AdDataStatus>({\n name: \"status\",\n schemaName: \"status\",\n schemaDescription:\n \"How fresh the stored ad data is: per platform, whether it is connected, when it last synced, any sync error, and per selected ad account the days stored, whether its history has finished loading, and adsInManyAdGroups — ads whose numbers in the last 30 days came from more than one ad group or campaign and are added together under one ad.\",\n help: \"How fresh the stored ad data is. Example: baker ads performance status\",\n path: \"status\",\n args: STATUS_ARGS,\n request: statusRequest,\n input: () => ({}),\n compact: compactStatus,\n hints: statusHints,\n});\n\nconst GETTING_WORSE_NOTE =\n \"Recent = the last 2 settled weeks, baseline = the 4 before (each platform's last settled day: asOf). Judged on what the entity is for (ROAS for sales with value, cost per result for leads, cost per click for traffic, CPM for awareness), falling back to an upstream metric when results are too few (judged.fallbackFrom). Status: worsening | improving | steady | mixed | not_comparable (its goal or counting changed) | too_early | too_little_data | stopped; confidence strong | moderate | weak.\";\n\nconst progressCommand = report<typeof adPerformanceProgressRequestSchema, AdPerformanceProgressData>({\n name: \"progress\",\n schemaName: \"progress\",\n schemaDescription: `Is it really getting better or worse? Every campaign, ad group or ad, worst first: status, confidence, the judged metric recent vs baseline, money at stake, a headline that says why (a measurement change, the market, scaling, fatigue, one child, the landing page…), what to check next, and the weekly line. --status filters, e.g. worsening,mixed. ${GETTING_WORSE_NOTE} ${STORE_NOTE}`,\n help: \"Worst-first: what is really getting worse, and why. Example: baker ads performance progress --level campaign --status worsening\",\n path: \"progress\",\n args: PROGRESS_ARGS,\n request: adPerformanceProgressRequestSchema,\n input: progressInput,\n compact: compactProgress,\n hints: progressHints,\n});\n\nconst diagnoseCommand = report<typeof adPerformanceDiagnosisRequestSchema, AdPerformanceDiagnosisData>({\n name: \"diagnose\",\n schemaName: \"diagnose\",\n schemaDescription: `Why one campaign, ad group or ad is getting better or worse: status and confidence, the judged metric, which part of the chain moved (impression prices, click rate, conversion rate after the click), the marginal cost when scaling, every finding with what to check, its weekly line up to a year and the changes on it. Read it before acting on a decline. ${GETTING_WORSE_NOTE} ${STORE_NOTE}`,\n help: \"Why one entity is getting better or worse. Example: baker ads performance diagnose 120211 --platform meta --level campaign\",\n path: \"diagnose\",\n args: DIAGNOSE_ARGS,\n request: adPerformanceDiagnosisRequestSchema,\n input: diagnoseInput,\n compact: compactDiagnosis,\n hints: diagnosisHints,\n});\n\nconst pulseCommand = report<typeof adPerformancePulseRequestSchema, AdPerformancePulseData>({\n name: \"pulse\",\n schemaName: \"pulse\",\n schemaDescription:\n \"The daily pulse: per ad account, the last settled day against the 7 settled days before it — spend, results, cost per result, link CTR, CPM, frequency — with watch: true where the day is outside their usual range.\",\n help: \"Yesterday's settled day against the week before. Example: baker ads performance pulse\",\n path: \"pulse\",\n args: PULSE_ARGS,\n request: adPerformancePulseRequestSchema,\n input: pulseInput,\n compact: compactPulse,\n hints: pulseHints,\n});\n\nexport const performanceCommand = defineCommand({\n meta: {\n name: \"performance\",\n description: `Ad results across every connected platform (Meta, Google Ads, LinkedIn, X, ChatGPT Ads), from Baker's stored copy: no platform call, history-complete. Read-only.\n\nStart here: baker ads performance overview\n baker ads performance attention — the few things that matter most right now\n baker ads performance trend --grain week --group-by campaign — spend and results over time, as the dashboard's charts\n baker ads performance entities --level ad --sort cost_per_result --order asc\n baker ads performance entity <id> --platform meta --level campaign — before any change\n baker ads performance impact --actor-kinds baker — did Baker's changes work\n baker ads performance progress --status worsening — what is really getting worse, and why\n baker ads performance anomalies — unusual days, and whether conversion events still record\n baker ads performance recap — this week's changes in plain sentences\n baker ads performance google-report --days 7 — a whole Google Ads review: brand vs non-brand, impression share, keywords, budgets\n baker ads performance live-in --landing <slug> — which live campaigns use a landing (or --creative <slug>) before you change it\n baker ads performance status — how fresh the synced copy is\nRead every number here first: no rate limit, full history, a few hours behind. Live baker ads <platform> reads only for today's numbers or what this lacks.\nFull guide: __tooling__/docs/tools/baker/ads-performance.md`,\n },\n subCommands: {\n overview: overviewCommand,\n trend: trendCommand,\n accounts: accountsCommand,\n setup: setupCommand,\n entities: entitiesCommand,\n entity: entityCommand,\n changes: changesCommand,\n impact: impactCommand,\n creatives: creativesCommand,\n families: familiesCommand,\n \"creative-health\": creativeHealthCommand,\n \"creative-assets\": creativeAssetsCommand,\n health: healthCommand,\n breakdown: breakdownCommand,\n \"search-terms\": searchTermsCommand,\n pacing: pacingCommand,\n funnel: funnelCommand,\n tracking: trackingCommand,\n landings: landingsCommand,\n \"live-in\": liveInCommand,\n status: statusCommand,\n goals: withWrites(goalsCommand, { set: goalsSetCommand, name: goalsNameCommand }),\n people: peopleOutcomesCommand,\n personas: personasCommand,\n ladder: ladderCommand,\n \"persona-fields\": personaFieldsCommand,\n progress: progressCommand,\n diagnose: diagnoseCommand,\n pulse: pulseCommand,\n anomalies: anomaliesCommand,\n recap: recapCommand,\n targets: withWrites(targetsCommand, {\n set: targetsSetCommand,\n \"alert-lines\": targetsAlertLinesCommand,\n unstage: targetsUnstageCommand,\n }),\n \"budget-recommendations\": budgetRecommendationsCommand,\n attention: attentionCommand,\n currency: currencyCommand,\n ...searchCommands,\n },\n});\n","/**\n * The flags of `baker ads performance` and how they become a request. Pure:\n * the citty arg definitions, and the mapping from parsed args to the request\n * the `@baker/api/ads-performance` schemas then validate.\n */\n\nimport type { ArgsDef } from \"citty\";\n\n/** Every amount in one currency, so accounts in different currencies add up and compare. */\nexport const REPORT_CURRENCY_ARG = {\n type: \"string\",\n description:\n \"Show every amount in this currency (ISO code, e.g. EUR), converted at the period's average ECB rate, or native for each ad account's own (default: the company's reporting currency, as the dashboard shows it)\",\n required: false,\n} as const;\n\n/** Flags every windowed report shares. */\nexport const SCOPE_ARGS = {\n days: {\n type: \"string\",\n description: \"Complete days back from yesterday (default 30). Use this or --start/--end\",\n required: false,\n },\n start: { type: \"string\", description: \"First day, YYYY-MM-DD (instead of --days)\", required: false },\n end: {\n type: \"string\",\n description: \"Last day, YYYY-MM-DD (default yesterday, or today when --start is today; needs --start)\",\n required: false,\n },\n platforms: {\n type: \"string\",\n description: \"Comma list of meta,google,linkedin,x,chatgpt (default all connected)\",\n required: false,\n },\n \"ad-account-ids\": {\n type: \"string\",\n description: \"Comma list of ad account ids (default all selected)\",\n required: false,\n },\n \"campaign-ids\": { type: \"string\", description: \"Comma list of campaign ids\", required: false },\n currency: REPORT_CURRENCY_ARG,\n full: {\n type: \"boolean\",\n description: \"Every field the store returns, unrounded, instead of the compact view\",\n required: false,\n default: false,\n },\n} as const;\n\nconst PAGE_ARGS = {\n limit: { type: \"string\", description: \"Rows to return\", required: false },\n offset: { type: \"string\", description: \"Rows to skip, for the next page\", required: false },\n} as const;\n\nconst ORDER_ARG = { type: \"string\", description: \"desc (default) or asc\", required: false } as const;\n\nexport const ENTITIES_ARGS = {\n ...SCOPE_ARGS,\n level: { type: \"string\", description: \"campaign (default), ad_group, ad or keyword\", required: false },\n \"ad-group-ids\": { type: \"string\", description: \"Comma list of ad group / ad set ids\", required: false },\n \"entity-ids\": {\n type: \"string\",\n description: \"Comma list of ids at --level: only these rows (e.g. the ids a visit or another read named)\",\n required: false,\n },\n statuses: {\n type: \"string\",\n description: \"Comma list: active,paused,scheduled,ended,in_review,rejected,draft,archived,removed\",\n required: false,\n },\n search: { type: \"string\", description: \"Only names containing this text\", required: false },\n sort: {\n type: \"string\",\n description:\n \"spend (default), impressions, clicks, link_clicks, results, result_value, cost_per_result, ctr, first_delivery, last_delivery, name\",\n required: false,\n },\n order: ORDER_ARG,\n ...PAGE_ARGS,\n \"include-idle\": {\n type: \"boolean\",\n description: \"Also list entities that did not deliver in the window\",\n required: false,\n default: false,\n },\n compare: {\n type: \"boolean\",\n description:\n \"Compare each row's settled days with as many days before (comparison.deltas); also lists what stopped delivering\",\n required: false,\n default: false,\n },\n segments: {\n type: \"string\",\n description: \"Google Search only: comma list of brand, competitor, non_brand, other, unsorted\",\n required: false,\n },\n} as const;\n\n/** `--days` with a read's own default, where it is not the 30 every other read takes. */\nfunction daysWithDefault(days: number) {\n return { ...SCOPE_ARGS.days, description: SCOPE_ARGS.days.description.replace(\"default 30\", `default ${days}`) };\n}\n\n/**\n * The window and scope of a read about one entity (`entity`, `diagnose`): the\n * read is keyed on `--platform` and the id, so `--platforms` and\n * `--campaign-ids` would be accepted and change nothing.\n */\nexport const ONE_ENTITY_SCOPE_ARGS = {\n days: SCOPE_ARGS.days,\n start: SCOPE_ARGS.start,\n end: SCOPE_ARGS.end,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n currency: SCOPE_ARGS.currency,\n full: SCOPE_ARGS.full,\n} as const;\n\nexport const ENTITY_ARGS = {\n id: { type: \"positional\", description: \"The campaign, ad group, ad or keyword id\", required: true },\n platform: { type: \"string\", description: \"meta, google, linkedin, x or chatgpt\", required: true },\n level: { type: \"string\", description: \"campaign, ad_group, ad or keyword\", required: true },\n \"ad-group-id\": { type: \"string\", description: \"The ad group of an ad or keyword, when known\", required: false },\n \"whole-run\": {\n type: \"boolean\",\n description:\n \"Read it over its first to last day of delivery (--whole-run) or only the period asked (--no-whole-run). Default: the period asked, unless it did not deliver in it, then its whole run. window shows the days read\",\n required: false,\n },\n ...ONE_ENTITY_SCOPE_ARGS,\n days: daysWithDefault(28),\n} as const;\n\nconst CHANGE_FILTER_ARGS = {\n kinds: {\n type: \"string\",\n description:\n \"Comma list: created,status,budget,bid,schedule,name,creative,targeting,goal,removed,other (goal = what it optimises for or how results are counted)\",\n required: false,\n },\n \"actor-kinds\": {\n type: \"string\",\n description: \"Comma list: person,platform_automatic,baker,unknown (baker = changes Baker published)\",\n required: false,\n },\n} as const;\n\nexport const CHANGES_ARGS = {\n ...SCOPE_ARGS,\n ...CHANGE_FILTER_ARGS,\n levels: { type: \"string\", description: \"Comma list: account,campaign,ad_group,ad,keyword\", required: false },\n \"entity-ids\": { type: \"string\", description: \"Comma list of entity ids\", required: false },\n sources: {\n type: \"string\",\n description: \"Comma list: baker (published from Baker), platform (the platform's change log), observed\",\n required: false,\n },\n ...PAGE_ARGS,\n} as const;\n\nexport const IMPACT_ARGS = {\n ...SCOPE_ARGS,\n days: daysWithDefault(60),\n ...CHANGE_FILTER_ARGS,\n \"impact-days\": {\n type: \"string\",\n description: \"Days compared on each side of a change, 3-28 (default 7)\",\n required: false,\n },\n ...PAGE_ARGS,\n} as const;\n\nexport const CREATIVES_ARGS = {\n ...SCOPE_ARGS,\n \"group-by\": {\n type: \"string\",\n description: \"creative (default: the same creative across ads counts once) or ad\",\n required: false,\n },\n \"ad-group-ids\": {\n type: \"string\",\n description: \"Comma list of ad group / ad set ids: only their ads' creatives\",\n required: false,\n },\n \"creative-keys\": {\n type: \"string\",\n description: \"Comma list of creative groupKeys (from a creatives row): only the ads running them\",\n required: false,\n },\n statuses: ENTITIES_ARGS.statuses,\n \"min-spend\": { type: \"string\", description: \"Least spend to be listed (default 0)\", required: false },\n \"min-impressions\": { type: \"string\", description: \"Least impressions to be listed (default 1000)\", required: false },\n limit: PAGE_ARGS.limit,\n} as const;\n\nexport const BREAKDOWN_ARGS = {\n ...SCOPE_ARGS,\n dimension: {\n type: \"string\",\n description: \"placement, country or device; Meta only: age, gender or audience_segment\",\n required: true,\n },\n} as const;\n\nexport const SEARCH_TERMS_ARGS = {\n ...SCOPE_ARGS,\n \"ad-group-ids\": ENTITIES_ARGS[\"ad-group-ids\"],\n \"min-clicks\": { type: \"string\", description: \"Least clicks to be listed (default 1)\", required: false },\n \"zero-results\": {\n type: \"boolean\",\n description: \"Only terms with no conversions: the negative-keyword candidates\",\n required: false,\n default: false,\n },\n search: { type: \"string\", description: \"Only terms containing this text\", required: false },\n sort: {\n type: \"string\",\n description: \"spend (default), clicks, conversions or cost_per_conversion\",\n required: false,\n },\n order: ORDER_ARG,\n ...PAGE_ARGS,\n \"term-segments\": {\n type: \"string\",\n description: \"Comma list: brand, competitor, non_brand, unsorted — what each term was read as\",\n required: false,\n },\n \"campaign-segments\": {\n type: \"string\",\n description: \"Comma list: brand, competitor, non_brand, other — the segment of the campaign that bought it\",\n required: false,\n },\n unsure: {\n type: \"boolean\",\n description: \"Only terms Baker was unsure how to sort: settle them with segments set --term\",\n required: false,\n default: false,\n },\n} as const;\n\nexport const PACING_ARGS = {\n month: {\n type: \"string\",\n description: \"YYYY-MM (default the current month; on the 1st, the month just ended)\",\n required: false,\n },\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n currency: REPORT_CURRENCY_ARG,\n full: SCOPE_ARGS.full,\n} as const;\n\nexport const FUNNEL_ARGS = {\n ...SCOPE_ARGS,\n level: { type: \"string\", description: \"campaign (default), ad_group or ad\", required: false },\n \"by-landing\": {\n type: \"boolean\",\n description: \"Split the visits by the page they entered on\",\n required: false,\n default: false,\n },\n limit: {\n type: \"string\",\n description:\n \"Entity rows to return (default 50, max 2000); untagged-visit rows (one per platform, per page with --by-landing) are added on top.\",\n required: false,\n },\n} as const;\n\n/**\n * `tracking` and `landings`: the ad half narrows by account and campaign, the\n * site visits never do (the store cannot tie a visit to an ad account).\n */\nexport const TRACKING_ARGS = {\n ...SCOPE_ARGS,\n \"ad-account-ids\": {\n ...SCOPE_ARGS[\"ad-account-ids\"],\n description:\n \"Comma list of ad account ids (default all selected). Narrows the ad numbers only: the site's visits are not narrowed\",\n },\n \"campaign-ids\": {\n ...SCOPE_ARGS[\"campaign-ids\"],\n description: \"Comma list of campaign ids. Narrows the ad numbers only: the site's visits are not narrowed\",\n },\n} as const;\n\nexport const GOALS_ARGS = {\n days: {\n type: \"string\",\n description: \"How far back to look for conversion actions, 7-400 (default 90). Use this or --start/--end\",\n required: false,\n },\n start: { type: \"string\", description: \"First day, YYYY-MM-DD (with --end, instead of --days)\", required: false },\n end: { type: \"string\", description: \"Last day, YYYY-MM-DD (with --start)\", required: false },\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n full: SCOPE_ARGS.full,\n} as const;\n\nexport const STATUS_ARGS = { full: SCOPE_ARGS.full } as const;\n\n// --- arg → request ---\n\ntype Args = Record<string, unknown>;\n\nexport function optionalString(raw: unknown): string | undefined {\n return typeof raw === \"string\" && raw.trim() !== \"\" ? raw.trim() : undefined;\n}\n\nexport function optionalNumber(raw: unknown): number | undefined {\n return typeof raw === \"string\" && raw.trim() !== \"\" ? Number(raw) : undefined;\n}\n\n/** A comma list as its non-empty items; absent when the flag was not passed. */\nexport function commaList(raw: unknown): string[] | undefined {\n const value = optionalString(raw);\n if (value === undefined) return undefined;\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter((item) => item !== \"\");\n}\n\n/**\n * Flags of `argsDef` passed with nothing in them (`--ad-account-ids \",\"`,\n * `--landing \"\"`), as issues naming each: the list parses empty, and an empty\n * list or an absent value means \"all\", so the read widened to everything\n * instead of narrowing.\n */\nexport function emptyFlagIssues(args: Args, argsDef: ArgsDef): Array<{ path: string[]; message: string }> {\n return Object.entries(argsDef)\n .filter(([name, def]) => def.type === \"string\" && typeof args[name] === \"string\" && /^[\\s,]*$/.test(args[name]))\n .map(([name]) => ({\n path: [name],\n message: \"was passed with nothing in it, which would read everything; name at least one, or leave the flag out\",\n }));\n}\n\nconst ENUM_ALIASES: Record<string, string> = {\n adset: \"ad_group\",\n ad_set: \"ad_group\",\n adgroup: \"ad_group\",\n google_ads: \"google\",\n facebook: \"meta\",\n twitter: \"x\",\n};\n\n/** An enum value as the schema spells it: lowercase, `-` as `_`, common aliases (`adset`, `google-ads`) mapped. */\nexport function enumValue(raw: unknown): string | undefined {\n const value = optionalString(raw)?.toLowerCase().replaceAll(\"-\", \"_\");\n return value === undefined ? undefined : (ENUM_ALIASES[value] ?? value);\n}\n\nfunction enumList(raw: unknown): string[] | undefined {\n return commaList(raw)?.map((item) => enumValue(item) ?? item);\n}\n\nexport function scopeInput(args: Args) {\n return {\n days: optionalNumber(args.days),\n start: optionalString(args.start),\n end: optionalString(args.end),\n platforms: enumList(args.platforms),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n campaignIds: commaList(args[\"campaign-ids\"]),\n currency: optionalString(args.currency),\n };\n}\n\nexport function entitiesInput(args: Args) {\n return {\n ...scopeInput(args),\n level: enumValue(args.level),\n adGroupIds: commaList(args[\"ad-group-ids\"]),\n entityIds: commaList(args[\"entity-ids\"]),\n statuses: enumList(args.statuses),\n search: optionalString(args.search),\n sort: enumValue(args.sort),\n order: enumValue(args.order),\n limit: optionalNumber(args.limit),\n offset: optionalNumber(args.offset),\n includeIdle: args[\"include-idle\"] === true,\n compare: args.compare === true,\n segments: enumList(args.segments),\n };\n}\n\n/** The scope of a read about one entity: only what `ONE_ENTITY_SCOPE_ARGS` can set. */\nexport function oneEntityScopeInput(args: Args) {\n const { days, start, end, adAccountIds, currency } = scopeInput(args);\n return { days, start, end, adAccountIds, currency };\n}\n\nexport function entityInput(args: Args) {\n return {\n ...oneEntityScopeInput(args),\n platform: enumValue(args.platform),\n level: enumValue(args.level),\n entityId: optionalString(args.id),\n adGroupId: optionalString(args[\"ad-group-id\"]),\n wholeRun: typeof args[\"whole-run\"] === \"boolean\" ? args[\"whole-run\"] : undefined,\n };\n}\n\nexport function changesInput(args: Args) {\n return {\n ...scopeInput(args),\n kinds: enumList(args.kinds),\n levels: enumList(args.levels),\n entityIds: commaList(args[\"entity-ids\"]),\n sources: enumList(args.sources),\n actorKinds: enumList(args[\"actor-kinds\"]),\n limit: optionalNumber(args.limit),\n offset: optionalNumber(args.offset),\n };\n}\n\nexport function impactInput(args: Args) {\n return {\n ...scopeInput(args),\n kinds: enumList(args.kinds),\n actorKinds: enumList(args[\"actor-kinds\"]),\n impactDays: optionalNumber(args[\"impact-days\"]),\n limit: optionalNumber(args.limit),\n offset: optionalNumber(args.offset),\n };\n}\n\nexport function creativesInput(args: Args) {\n return {\n ...scopeInput(args),\n groupBy: enumValue(args[\"group-by\"]),\n adGroupIds: commaList(args[\"ad-group-ids\"]),\n creativeKeys: commaList(args[\"creative-keys\"]),\n statuses: enumList(args.statuses),\n minSpend: optionalNumber(args[\"min-spend\"]),\n minImpressions: optionalNumber(args[\"min-impressions\"]),\n limit: optionalNumber(args.limit),\n };\n}\n\nexport function breakdownInput(args: Args) {\n return { ...scopeInput(args), dimension: enumValue(args.dimension) };\n}\n\nexport function searchTermsInput(args: Args) {\n return {\n ...scopeInput(args),\n adGroupIds: commaList(args[\"ad-group-ids\"]),\n minClicks: optionalNumber(args[\"min-clicks\"]),\n noResults: args[\"zero-results\"] === true,\n search: optionalString(args.search),\n sort: enumValue(args.sort),\n order: enumValue(args.order),\n limit: optionalNumber(args.limit),\n offset: optionalNumber(args.offset),\n termSegments: enumList(args[\"term-segments\"]),\n campaignSegments: enumList(args[\"campaign-segments\"]),\n unsureOnly: args.unsure === true,\n };\n}\n\nexport function pacingInput(args: Args) {\n return {\n month: optionalString(args.month),\n platforms: enumList(args.platforms),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n currency: optionalString(args.currency),\n };\n}\n\nexport function funnelInput(args: Args) {\n return {\n ...scopeInput(args),\n level: enumValue(args.level),\n byLanding: args[\"by-landing\"] === true,\n limit: optionalNumber(args.limit),\n };\n}\n\nexport function goalsInput(args: Args) {\n return {\n days: optionalNumber(args.days),\n start: optionalString(args.start),\n end: optionalString(args.end),\n platforms: enumList(args.platforms),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n };\n}\n\n/**\n * Request fields named unlike their flag, as the flags that may set them: the\n * ones the refusing command has are named. A nested field is looked up by its\n * dotted path first (`target.segment`), then by its own name, then by its\n * parent's. Every other field's flag is its own name in kebab case.\n */\nconst FLAGS_OF_FIELD: Record<string, readonly string[]> = {\n entityId: [\"id\"],\n alertId: [\"id\"],\n noResults: [\"zero-results\"],\n unsureOnly: [\"unsure\"],\n includeDismissed: [\"dismissed\"],\n statuses: [\"statuses\", \"status\"],\n adAccountId: [\"account\"],\n value: [\"cost\", \"roas\", \"amount\"],\n metric: [\"cost\", \"roas\"],\n note: [\"note\", \"reason\"],\n countText: [\"count\"],\n uncountText: [\"uncount\"],\n brandNames: [\"brand\"],\n competitorNames: [\"competitors\"],\n kind: [\"campaign\", \"term\"],\n key: [\"key\", \"campaign\", \"term\"],\n \"target.segment\": [\"target\"],\n granularity: [\"grain\"],\n costPerResultRisePct: [\"cost-rise-pct\"],\n label: [\"name\"],\n};\n\nfunction kebab(field: string): string {\n return field.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n\nfunction candidatesOf(field: string): string[] {\n return [...new Set([...(FLAGS_OF_FIELD[field] ?? []), kebab(field)])];\n}\n\n/** How a flag is written: `--name`, or bare for a positional (and for `id` when the command is unknown). */\nfunction written(name: string, args?: ArgsDef): string {\n return args?.[name]?.type === \"positional\" || (args === undefined && name === \"id\") ? name : `--${name}`;\n}\n\n/** The flags of `args` that set the field at `path`, or none when the command has no such flag. */\nfunction flagsOf(path: string[], args: ArgsDef): string[] {\n const names = path.filter((part) => !/^\\d+$/.test(part));\n const lookups = [names.join(\".\"), names.at(-1), names[0]].filter((name) => name !== undefined);\n for (const lookup of lookups) {\n const present = candidatesOf(lookup).filter((candidate) => candidate in args);\n if (present.length > 0) return present.map((name) => written(name, args));\n }\n return [];\n}\n\nfunction describeField(path: string[], args?: ArgsDef): string {\n const [field = \"\", ...rest] = path;\n const flags = args === undefined ? [] : flagsOf(path, args);\n if (flags.length > 0) {\n const indices = path.filter((part) => /^\\d+$/.test(part));\n return `${flags.join(\" or \")}${indices.length > 0 ? ` (item ${indices.join(\".\")})` : \"\"}`;\n }\n const item = rest.length > 0 ? ` (item ${rest.join(\".\")})` : \"\";\n return `${written(candidatesOf(field)[0] ?? field, args)}${item}`;\n}\n\n/** A refused request in the agent's own words: which flag of the command (`args`), and why. */\nexport function invalidArgsMessage(\n issues: ReadonlyArray<{ path: PropertyKey[]; message: string }>,\n args?: ArgsDef,\n): string {\n return issues\n .map((issue) => {\n const path = issue.path.map(String);\n if (path.length === 0) return `args: ${issue.message}`;\n return `${describeField(path, args)}: ${issue.message}`;\n })\n .join(\"; \");\n}\n","/**\n * `baker ads performance targets set | targets alert-lines | targets unstage | goals set | goals name` — the\n * agent's changes to a company's targets (per ad account and event, per\n * account, or the company default), its two alert lines, what counts as a\n * result at an ad account, and what the company calls one result. Every one\n * stages on this chat and applies when the person publishes it\n * (`convex/adPerformance/goalDrafts.ts`); nothing changes before.\n */\n\nimport {\n adGoalUnstageRequestSchema,\n adResultsStageRequestSchema,\n adTargetStageRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { adAlertLinesStageRequestSchema, adResultNameStageRequestSchema } from \"@baker/api/ads-performance/targets\";\nimport { type ArgsDef, type CommandDef, defineCommand } from \"citty\";\nimport type { z } from \"zod\";\nimport { apiPost } from \"../../../client.ts\";\nimport { requireChatId } from \"../../../env.ts\";\nimport { writeJson } from \"../../../output.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { failApi } from \"../../actions/shared.ts\";\nimport { enumValue, optionalNumber } from \"./args.ts\";\nimport { failInvalid } from \"./reportCommand.ts\";\n\ntype Args = Record<string, unknown>;\n\nconst text = (raw: unknown) => (typeof raw === \"string\" && raw.trim() !== \"\" ? raw.trim() : undefined);\n\n// --- pure: flags → request ---\n\nexport function targetSetInput(args: Args, chatId: string): Record<string, unknown> {\n const cost = optionalNumber(args.cost);\n const roas = optionalNumber(args.roas);\n const platform = text(args.platform);\n return {\n chatId,\n ...(args.company === true ? { company: true } : {}),\n ...(platform ? { platform: enumValue(platform) ?? platform } : {}),\n ...(text(args.account) ? { adAccountId: text(args.account) } : {}),\n ...(text(args.event) ? { event: text(args.event) } : {}),\n ...(roas !== undefined ? { metric: \"roas\" } : cost !== undefined ? { metric: \"cost_per_result\" } : {}),\n value: args.clear === true ? null : (roas ?? cost),\n ...(text(args.currency) ? { currency: text(args.currency) } : {}),\n };\n}\n\n/**\n * Conversion action names, comma-separated. A Google action's own name can\n * hold a comma (\"Leads, all\"): written `\\,` it stays in the name. The value\n * as written also travels whole, so the backend keeps it as one action when\n * the account has one by that exact name.\n */\nfunction actionNames(raw: unknown): { names: string[]; text?: string } {\n const value = text(raw);\n if (value === undefined) return { names: [] };\n const names = value\n .split(/(?<!\\\\),/)\n .map((name) => name.replaceAll(\"\\\\,\", \",\").trim())\n .filter((name) => name !== \"\");\n return { names, text: value.replaceAll(\"\\\\,\", \",\") };\n}\n\nexport function goalsSetInput(args: Args, chatId: string): Record<string, unknown> {\n const platform = text(args.platform);\n const count = actionNames(args.count);\n const uncount = actionNames(args.uncount);\n return {\n chatId,\n ...(platform ? { platform: enumValue(platform) ?? platform } : {}),\n ...(text(args.account) ? { adAccountId: text(args.account) } : {}),\n count: count.names,\n uncount: uncount.names,\n ...(count.text ? { countText: count.text } : {}),\n ...(uncount.text ? { uncountText: uncount.text } : {}),\n ...(args.reset === true ? { reset: true } : {}),\n };\n}\n\nexport function resultNameInput(args: Args, chatId: string): Record<string, unknown> {\n return {\n chatId,\n ...(text(args.singular) ? { singular: text(args.singular) } : {}),\n ...(text(args.plural) ? { plural: text(args.plural) } : {}),\n ...(args.reset === true ? { reset: true } : {}),\n };\n}\n\n/** An alert line as written: a percent, or `default` for Baker's own (null). Absent when the flag was not passed. */\nfunction alertLine(raw: unknown): number | null | undefined {\n const value = text(raw);\n if (value === undefined) return undefined;\n return value.toLowerCase() === \"default\" ? null : Number(value.replace(/%$/, \"\"));\n}\n\nexport function alertLinesInput(args: Args, chatId: string): Record<string, unknown> {\n const rise = alertLine(args[\"cost-rise-pct\"]);\n const overspend = alertLine(args[\"overspend-pct\"]);\n return {\n chatId,\n ...(rise === undefined ? {} : { costPerResultRisePct: rise }),\n ...(overspend === undefined ? {} : { overspendPct: overspend }),\n };\n}\n\n/** Whether a flag was given: a boolean set, or a value that is not blank. */\nfunction given(raw: unknown): boolean {\n return raw === true || text(raw) !== undefined;\n}\n\n/**\n * Flags that cannot go together, said by name (`--cost or --roas: pass one,\n * not both`), or null. Each group lists sides that exclude each other; a side\n * is one or more flags that may go together. Without it one flag silently\n * wins and the agent stages what it did not ask for.\n */\nexport function flagConflict(\n args: Args,\n exclusive: ReadonlyArray<ReadonlyArray<readonly string[]>>,\n defs: ArgsDef,\n): string | null {\n const written = (flag: string) => (defs[flag]?.type === \"positional\" ? `<${flag}>` : `--${flag}`);\n for (const sides of exclusive) {\n const present = sides\n .map((side) => side.filter((flag) => given(args[flag])))\n .filter((flags) => flags.length > 0)\n .map((flags) => flags.map(written).join(\" and \"));\n if (present.length < 2) continue;\n const named = `${present.slice(0, -1).join(\", \")} or ${present.at(-1)}`;\n return `${named}: pass one, ${present.length === 2 ? \"not both\" : \"not several\"}.`;\n }\n return null;\n}\n\nfunction failConflict(message: string): never {\n writeJson({ ok: false, error: { code: \"INVALID_ARGS\", message } });\n process.exit(1);\n}\n\n// --- commands ---\n\nconst ACCOUNT_ARGS = {\n platform: { type: \"string\", description: \"meta | google | linkedin | x | chatgpt\", required: false },\n account: {\n type: \"string\",\n description: \"The ad account id, as baker ads performance targets lists it\",\n required: false,\n },\n} as const;\n\nconst TARGET_SET_ARGS = {\n ...ACCOUNT_ARGS,\n company: { type: \"boolean\", description: \"The company default instead of one ad account\", required: false },\n event: {\n type: \"string\",\n description:\n \"A conversion action key from baker ads performance targets (events[].event): the target for that event only. Meta and LinkedIn only; elsewhere omit it to set the account's target\",\n required: false,\n },\n cost: { type: \"string\", description: \"Target cost per result (needs --currency)\", required: false },\n currency: { type: \"string\", description: \"The cost's currency, e.g. EUR\", required: false },\n roas: { type: \"string\", description: \"Target return on ad spend, as a ratio (3 = 3×)\", required: false },\n clear: { type: \"boolean\", description: \"Remove the target\", required: false },\n} as const;\n\nconst GOALS_SET_ARGS = {\n ...ACCOUNT_ARGS,\n count: {\n type: \"string\",\n description:\n \"Comma list of conversion action keys to count as results, exactly as baker ads performance targets lists them. A comma inside one name is written \\\\, (--count 'Leads\\\\, all,Calls'): a comma list that splits into a name the account does not have is refused with the escaped form and the closest names; a single name it has not seen convert stages with a spelling hint\",\n required: false,\n },\n uncount: {\n type: \"string\",\n description: \"Comma list of conversion action keys to stop counting (a comma inside one name is written \\\\,)\",\n required: false,\n },\n reset: {\n type: \"boolean\",\n description: \"Drop this account's own choice: it follows what its platform counts for every account\",\n required: false,\n },\n} as const;\n\nconst RESULT_NAME_ARGS = {\n singular: {\n type: \"string\",\n description: 'One result, as the person says it: \"lead\", \"demo request\"',\n required: false,\n },\n plural: { type: \"string\", description: 'Several: \"leads\", \"demo requests\"', required: false },\n reset: {\n type: \"boolean\",\n description: \"Drop the company's own name: Baker names results from what the goals count again\",\n required: false,\n },\n} as const;\n\nconst ALERT_LINES_ARGS = {\n \"cost-rise-pct\": {\n type: \"string\",\n description:\n \"Alert when cost per result rises this many percent over the weeks before: 10-300 (Baker's default 20), or default to go back to it\",\n required: false,\n },\n \"overspend-pct\": {\n type: \"string\",\n description:\n \"Alert when a day's spend passes this percent of its daily budget and of its usual spend: 110-500 (Baker's default 160), or default\",\n required: false,\n },\n} as const;\n\nconst UNSTAGE_ARGS = {\n key: { type: \"positional\", description: \"A staged key from baker ads performance targets → staged\", required: false },\n all: { type: \"boolean\", description: \"Take back every staged goal and target on this chat\", required: false },\n} as const;\n\nexport function writeCommand<S extends z.ZodType>(spec: {\n name: string;\n schemaName: string;\n schemaDescription: string;\n help: string;\n path: string;\n args: ArgsDef;\n request: S;\n input: (args: Args, chatId: string) => unknown;\n /** Flags that cannot go together (`flagConflict`), refused before anything is sent. */\n exclusive?: ReadonlyArray<ReadonlyArray<readonly string[]>>;\n}): CommandDef {\n registerSchema({\n command: `ads.performance.${spec.schemaName}`,\n description: spec.schemaDescription,\n args: spec.args as Parameters<typeof registerSchema>[0][\"args\"],\n });\n return defineCommand({\n meta: { name: spec.name, description: spec.help },\n args: spec.args,\n run: async ({ args }) => {\n try {\n const conflict = spec.exclusive ? flagConflict(args, spec.exclusive, spec.args) : null;\n if (conflict) failConflict(conflict);\n const parsed = spec.request.safeParse(spec.input(args, requireChatId()));\n if (!parsed.success) failInvalid(parsed.error.issues, spec.args);\n writeJson(await apiPost<{ ok: true; data: unknown; hints?: string[] }>(spec.path, parsed.data));\n } catch (err) {\n failApi(err);\n }\n },\n });\n}\n\nexport const targetsSetCommand = writeCommand({\n name: \"set\",\n schemaName: \"targets.set\",\n schemaDescription:\n \"Stage one target on this chat; it applies when the person publishes the chat, never before. The target of one event at an ad account (--platform --account --event, Meta and LinkedIn only), of an ad account's whole result (--platform --account), or the company default (--company). --cost 25 --currency EUR judges cost per result; --roas 3 judges return on ad spend; --clear removes it. Restaging the same target replaces it. Publish leaves a target a person changed in the dashboard meanwhile as they set it and reports yours as not applied. Ask the person before staging: a target is what the business can afford, and every alert and budget recommendation judges against it.\",\n help: \"Stage a target; it applies when the chat is published.\\n\\nExamples:\\n baker ads performance targets set --platform meta --account 123 --event offsite_conversion.fb_pixel_lead --cost 25 --currency EUR\\n baker ads performance targets set --platform google --account 456 --roas 4\\n baker ads performance targets set --company --cost 30 --currency EUR\\n baker ads performance targets set --platform meta --account 123 --clear\",\n path: \"/api/ads/performance/targets/set\",\n args: TARGET_SET_ARGS,\n request: adTargetStageRequestSchema,\n input: targetSetInput,\n exclusive: [[[\"clear\"], [\"cost\"], [\"roas\"]]],\n});\n\nexport const goalsSetCommand = writeCommand({\n name: \"set\",\n schemaName: \"goals.set\",\n schemaDescription:\n \"Stage what counts as a result at one ad account (--platform --account): --count adds conversion action keys, --uncount removes them, --reset drops the account's own choice so it follows its platform's. Applies when the person publishes the chat, and then re-scores the account's whole history; a choice a person changed meanwhile stays as they set it. Use the action keys baker ads performance targets (events[].event, available[].event) or baker ads performance goals lists, exactly. A Google action's own name can hold a comma: write it \\\\, (--count 'Leads\\\\, all'). A comma list that splits into a name the account does not have is refused (error.fix.escaped, error.fix.unknown[].closest); a single name it has not recorded a conversion for in 400 days stages with a hint to check the spelling.\",\n help: \"Stage what counts as a result at an ad account.\\n\\nExamples:\\n baker ads performance goals set --platform meta --account 123 --count offsite_conversion.fb_pixel_lead\\n baker ads performance goals set --platform google --account 456 --uncount Calls\\n baker ads performance goals set --platform google --account 456 --count 'Leads\\\\, all,Calls'\\n baker ads performance goals set --platform meta --account 123 --reset\",\n path: \"/api/ads/performance/goals/set\",\n args: GOALS_SET_ARGS,\n request: adResultsStageRequestSchema,\n input: goalsSetInput,\n exclusive: [[[\"reset\"], [\"count\", \"uncount\"]]],\n});\n\nexport const goalsNameCommand = writeCommand({\n name: \"name\",\n schemaName: \"goals.name\",\n schemaDescription:\n 'Stage what the company calls one result, for every ad account: --singular \"demo request\" --plural \"demo requests\" (both), or --reset to name results from what the goals count again. Applies when the person publishes the chat; then every Ads screen, the Measure overview and baker ads performance overview (resultNoun) use it. Only when the person says what they call a result (\"we call them sign-ups\"); never to relabel a count that mixes kinds.',\n help: 'Stage what the company calls one result.\\n\\nExamples:\\n baker ads performance goals name --singular \"demo request\" --plural \"demo requests\"\\n baker ads performance goals name --reset',\n path: \"/api/ads/performance/goals/name\",\n args: RESULT_NAME_ARGS,\n request: adResultNameStageRequestSchema,\n input: resultNameInput,\n});\n\nexport const targetsAlertLinesCommand = writeCommand({\n name: \"alert-lines\",\n schemaName: \"targets.alert-lines\",\n schemaDescription:\n \"Stage how sensitive two alerts are, for every ad account: --cost-rise-pct (alert when cost per result rises this many percent over the weeks before, 10-300) and --overspend-pct (alert when a day's spend passes this percent of its daily budget and of its usual spend, 110-500); either or both, or default to go back to Baker's (20 and 160 — read them with baker ads performance targets → alerts). Applies when the person publishes the chat; then every alert is judged again against the new line. A line a person changed meanwhile stays as they set it. Only when the person asks for fewer or more of these alerts: a higher line raises fewer.\",\n help: \"Stage the alert lines; they apply when the chat is published.\\n\\nExamples:\\n baker ads performance targets alert-lines --cost-rise-pct 40\\n baker ads performance targets alert-lines --overspend-pct 200 --cost-rise-pct default\",\n path: \"/api/ads/performance/targets/alert-lines\",\n args: ALERT_LINES_ARGS,\n request: adAlertLinesStageRequestSchema,\n input: alertLinesInput,\n});\n\nexport const targetsUnstageCommand = writeCommand({\n name: \"unstage\",\n schemaName: \"targets.unstage\",\n schemaDescription:\n \"Take back a goal or target this chat staged, before publish (a key from baker ads performance targets → staged, or --all). Never touches what is already in force.\",\n help: \"Take back a staged goal or target.\\n\\nExamples:\\n baker ads performance targets unstage target:meta:123:offsite_conversion.fb_pixel_lead\\n baker ads performance targets unstage --all\",\n path: \"/api/ads/performance/targets/unstage\",\n args: UNSTAGE_ARGS,\n request: adGoalUnstageRequestSchema,\n input: (args, chatId) => ({\n chatId,\n ...(text(args.key) ? { key: text(args.key) } : {}),\n ...(args.all === true ? { all: true } : {}),\n }),\n});\n\n/**\n * A read command that also has write subcommands. The read becomes the `show`\n * subcommand and the parent's `default`, never its `run`: citty falls through\n * to a parent's `run` after the subcommand it dispatched to. The parent\n * declares the read's flags so a bare `targets --days 30` reaches `show`.\n */\nexport function withWrites(read: CommandDef, writes: Record<string, CommandDef>): CommandDef {\n return defineCommand({\n meta: read.meta,\n args: read.args,\n subCommands: { show: read, ...writes },\n default: \"show\",\n });\n}\n","/**\n * The shape every `baker ads performance` read shares: flags parsed by the\n * request's shared schema, one POST to the store's route, asked once more\n * when the store is busy, compact by default and whole with `--full`, and the\n * refusals the agent can act on turned into a fix.\n */\n\nimport { ANALYTICS_BUSY_FIX, isAnalyticsBusy, retryOnceIfBusy } from \"@baker/api/analytics\";\nimport { type ArgsDef, defineCommand } from \"citty\";\nimport type { z } from \"zod\";\nimport { ApiError, apiPost } from \"../../../client.ts\";\nimport { writeJson } from \"../../../output.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { failApi } from \"../../actions/shared.ts\";\nimport { emptyFlagIssues, invalidArgsMessage } from \"./args.ts\";\nimport { adPerformanceRefusal, roundDeep } from \"./report.ts\";\n\n/** A request its schema refused, naming the command's own flags (`args`). */\nexport function failInvalid(issues: ReadonlyArray<{ path: PropertyKey[]; message: string }>, args: ArgsDef): never {\n writeJson({ ok: false, error: { code: \"INVALID_ARGS\", message: invalidArgsMessage(issues, args) } });\n process.exit(1);\n}\n\n/**\n * One read of the store: asked once more after a pause when it was busy, never\n * in a loop (`retryOnceIfBusy`). Reads only — a write is never sent twice.\n */\nexport function postRead<D>(path: string, body: unknown): Promise<{ ok: true; data: D }> {\n return retryOnceIfBusy(\n () => apiPost<{ ok: true; data: D }>(`/api/ads/performance/${path}`, body),\n (caught) => (caught instanceof Error ? caught.message : \"\"),\n );\n}\n\n/** \"Nothing connected\" and \"busy\" become the fix the agent relays; everything else is the ordinary error envelope. */\nexport function failRead(err: unknown): never {\n const refusal = err instanceof ApiError ? adPerformanceRefusal(err.code, err.message) : null;\n if (err instanceof ApiError && refusal !== null) {\n writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });\n process.exit(1);\n }\n if (err instanceof ApiError && isAnalyticsBusy(err.message)) {\n writeJson({ ok: false, error: { code: err.code, message: err.message, fix: ANALYTICS_BUSY_FIX } });\n process.exit(1);\n }\n failApi(err);\n}\n\ninterface ReportSpec<S extends z.ZodType, D> {\n name: string;\n schemaName: string;\n /** Agent-facing, for `baker schema`: what it answers and what it returns. */\n schemaDescription: string;\n /** Short, for `--help`: one line plus an example. */\n help: string;\n path: string;\n args: ArgsDef;\n request: S;\n input: (args: Record<string, unknown>) => unknown;\n compact?: (data: D) => unknown;\n /** `args` as typed, for a hint about a flag passed rather than its default. */\n hints?: (data: D, request: z.output<S>, args: Record<string, unknown>) => string[];\n}\n\nexport function report<S extends z.ZodType, D>(spec: ReportSpec<S, D>) {\n registerSchema({\n command: `ads.performance.${spec.schemaName}`,\n description: spec.schemaDescription,\n args: spec.args as Parameters<typeof registerSchema>[0][\"args\"],\n });\n return defineCommand({\n meta: { name: spec.name, description: spec.help },\n args: spec.args,\n run: async ({ args }) => {\n const empty = emptyFlagIssues(args, spec.args);\n if (empty.length > 0) failInvalid(empty, spec.args);\n const parsed = spec.request.safeParse(spec.input(args));\n if (!parsed.success) failInvalid(parsed.error.issues, spec.args);\n try {\n const response = await postRead<D>(spec.path, parsed.data);\n const hints = spec.hints?.(response.data, parsed.data, args) ?? [];\n const data = args.full === true ? response.data : (spec.compact ?? roundDeep)(response.data);\n writeJson({ ok: true, data, ...(hints.length > 0 ? { hints } : {}) });\n } catch (err) {\n failRead(err);\n }\n },\n });\n}\n\nexport const STORE_NOTE =\n \"Reads Baker's stored copy of every connected ad platform (busy accounts refreshed every few hours, quiet ones once or twice a day; no platform call). Results are the company's chosen goals, else each platform's headline conversions. Money is in the company's reporting currency, converted at the period's average ECB rate (--currency to pick another, native for each account's own); a currency with no rate keeps its own, so never add amounts across currencies. --full returns every field unrounded.\";\n","/**\n * `baker ads performance families`: the creatives the company launched,\n * grouped by their family in the winning-ads library or by what the library\n * read in them (hook, angle, framework, offer, style, …), with their real\n * spend and results — and the `library` part of each `creatives` row.\n * `families choices` reads the families an unsettled creative may be;\n * `families link` stages the one it is, applied when the chat is published.\n */\n\nimport {\n AD_CREATIVE_GROUPS,\n type AdCreativeLibraryLink,\n type AdLibraryChoicesData,\n type AdLibraryEvidence,\n type AdPerformanceFamiliesData,\n adLibraryChoicesRequestSchema,\n adLibraryLinkStageRequestSchema,\n adPerformanceFamiliesRequestSchema,\n} from \"@baker/api/ads-performance/library\";\nimport { enumValue, optionalNumber, optionalString, SCOPE_ARGS, scopeInput } from \"./args.ts\";\nimport { withWrites, writeCommand } from \"./goalWrites.ts\";\nimport { platformLabel, roundDeep, roundNumber } from \"./report.ts\";\nimport { report, STORE_NOTE } from \"./reportCommand.ts\";\n\ntype Args = Record<string, unknown>;\n\n/** What the agent needs of a creative's library link: the family, how sure, and the reading's main parts. */\nexport function compactLibraryLink(link: AdCreativeLibraryLink | null): Record<string, unknown> | \"unchecked\" {\n if (!link) return \"unchecked\";\n const analysis = link.analysis;\n const parts = {\n status: link.status,\n familyId: link.familyId,\n libraryAdId: link.adId,\n ...(link.otherFamilies > 0 ? { otherFamilies: link.otherFamilies } : {}),\n ...(link.notFoundReason ? { reason: link.notFoundReason } : {}),\n ...(link.chosen ? { chosenByPerson: true } : {}),\n hook: analysis?.hook,\n angle: analysis?.angleType,\n framework: analysis?.framework,\n offer: analysis?.offer,\n style: analysis?.style,\n libraryWinnerScore: link.libraryWinnerScore === null ? undefined : roundNumber(link.libraryWinnerScore),\n };\n return Object.fromEntries(Object.entries(parts).filter(([, value]) => value !== null && value !== undefined));\n}\n\n/** Each currency's cost per result across every group: what `vsAverage` divides by, as the screen's chip does. */\nfunction averageCosts(rows: AdPerformanceFamiliesData[\"rows\"]): Map<string, number | null> {\n const totals = new Map<string, { spend: number; results: number }>();\n for (const row of rows) {\n const total = totals.get(row.currency) ?? { spend: 0, results: 0 };\n totals.set(row.currency, { spend: total.spend + row.metrics.spend, results: total.results + row.metrics.results });\n }\n return new Map([...totals].map(([currency, t]) => [currency, t.results >= 1 ? t.spend / t.results : null]));\n}\n\nfunction vsAverage(cost: number | null, average: number | null | undefined): { vsAverage?: number } {\n return cost === null || !average ? {} : { vsAverage: cost / average };\n}\n\nexport function compactFamilies(data: AdPerformanceFamiliesData) {\n const averages = averageCosts(data.rows);\n return {\n window: data.window,\n by: data.by,\n brand: data.brand && { label: data.brand.label, status: data.brand.status, platforms: data.brand.platforms },\n coverage: roundDeep(data.coverage),\n rows: data.rows.map((row) =>\n roundDeep({\n key: row.key,\n label: row.label,\n currency: row.currency,\n creatives: row.creatives,\n activeCreatives: row.activeCreatives,\n spend: row.metrics.spend,\n results: row.metrics.results,\n costPerResult: row.ratios.costPerResult,\n ...vsAverage(row.ratios.costPerResult, averages.get(row.currency)),\n spendShare: row.spendShare,\n resultsShare: row.resultsShare,\n abovePeers: row.abovePeers,\n belowPeers: row.belowPeers,\n ...(row.analysis\n ? {\n hook: row.analysis.hook,\n angle: row.analysis.angleType,\n framework: row.analysis.framework,\n offer: row.analysis.offer,\n style: row.analysis.style,\n }\n : {}),\n ...(row.agreement ? { agreement: row.agreement } : {}),\n ...(row.library.bestWinnerScore !== null ? { libraryWinnerScore: row.library.bestWinnerScore } : {}),\n topCreative: row.top.groupKey,\n ...(row.top.libraryAdId ? { libraryAdId: row.top.libraryAdId, platform: row.top.platform } : {}),\n }),\n ),\n };\n}\n\n/** How a creative is staged into a family: the link is refused without the name the person knows it by. */\nconst LINK_COMMAND = 'baker ads performance families link <key> --family <familyId> --name \"<its name in creatives>\"';\n\n/** The key the library knows a creative by, as a `creatives` row says it. */\nconst CREATIVE_KEY_WORDS =\n \"its libraryKey from baker ads performance creatives (mediaKey with --full), else its groupKey\";\n\nexport function familiesHints(\n data: AdPerformanceFamiliesData,\n request: { platforms?: readonly string[] } = {},\n): string[] {\n if (!data.brand) {\n return [\n \"The brand's own ads are not in the winning-ads library yet: Baker follows the Facebook Page its Meta ads spend most on after the next sync. To add it now, or another platform's account: baker winning-ads follow <the brand's website or page>.\",\n ];\n }\n const hints: string[] = [];\n const inLibrary = data.brand.platforms;\n if (\n data.coverage.creatives === 0 &&\n request.platforms !== undefined &&\n !request.platforms.some((platform) => inLibrary.includes(platform))\n )\n hints.push(\n `The brand is in the winning-ads library on ${inLibrary.map(platformLabel).join(\" and \")} only: families reads creatives there. Drop --platforms, or name ${inLibrary.join(\",\")}.`,\n );\n if (data.brand.status === \"scanning\")\n hints.push(\"The library is still collecting the brand's ads: links and readings fill in as it finishes.\");\n const libraryOnly = data.rows.filter((row) => row.agreement === \"library_only\").length;\n if (libraryOnly > 0)\n hints.push(\n `${libraryOnly} families the library calls winners did no better than their ad-set peers here: its score reads how long and widely an ad ran, not what it brought — trust the money, and say which you used.`,\n );\n if (data.coverage.ambiguous > 0)\n hints.push(\n `${data.coverage.ambiguous} creatives fit more than one family (videos launched together under the same words); they sit under \"Unsorted\" until one is picked. Read the candidates with baker ads performance families choices <key> (${CREATIVE_KEY_WORDS}), and stage the one the person confirms: ${LINK_COMMAND}.`,\n );\n hints.push(\n \"Open a family's library ad with baker winning-ads content <libraryAdId> --platform <platform> for the full reading (transcript, on-screen text, pacing).\",\n );\n return hints;\n}\n\nconst familiesReadCommand = report<typeof adPerformanceFamiliesRequestSchema, AdPerformanceFamiliesData>({\n name: \"families\",\n schemaName: \"families\",\n schemaDescription: `The creatives the company launched, grouped by their family in the winning-ads library (--by family: the same creative across ad sets, accounts and re-uploads) or by what the library read in them (--by hook | angle | framework | offer | awareness | style | creator | mechanism), each group with its real spend, results, cost per result and vsAverage (its cost per result over the average of every group: 0.77 = 23% cheaper), share of spend and results, and how many of its creatives beat or fell behind their ad-group peers. Per family: the library's reading, its winner score (how long and widely the ad ran publicly — a guess) and agreement: both | library_only | ours_only | neither | unknown, the guess against the money. coverage says how many creatives are linked, likely, ambiguous, not in the library, or not checked (platforms the brand is not in the library on). Defaults to the platforms the brand is in the library on. ${STORE_NOTE}`,\n help: \"Launched creatives by library family or by hook, angle, framework… Example: baker ads performance families --by hook --days 90\",\n path: \"families\",\n args: {\n ...SCOPE_ARGS,\n by: {\n type: \"string\",\n description: `Group by: ${AD_CREATIVE_GROUPS.join(\" | \")} (default family)`,\n required: false,\n },\n \"min-spend\": { type: \"string\", description: \"Leave out creatives that spent less than this\", required: false },\n limit: { type: \"string\", description: \"Groups to return (default 25, max 100)\", required: false },\n },\n request: adPerformanceFamiliesRequestSchema,\n input: (args) => ({\n ...scopeInput(args),\n by: enumValue(args.by),\n minSpend: optionalNumber(args[\"min-spend\"]),\n limit: optionalNumber(args.limit),\n }),\n compact: compactFamilies,\n hints: familiesHints,\n});\n\n// --- choices and link ---\n\n/** Creative keys from the positional words, each also a comma list; in order, once each. */\nexport function familyChoicesInput(args: Args) {\n const words = [args.creatives, ...(Array.isArray(args._) ? args._ : [])];\n const keys = words.flatMap((word) => (typeof word === \"string\" ? word.split(\",\").map((key) => key.trim()) : []));\n const platform = enumValue(args.platform);\n return { creatives: [...new Set(keys.filter((key) => key !== \"\"))], ...(platform ? { platform } : {}) };\n}\n\nconst LANDING_WORDS: Record<AdLibraryEvidence[\"landing\"], string | null> = {\n same: \"same landing page\",\n same_site: \"same site\",\n different: \"different landing page\",\n unknown: null,\n};\n\nconst NOT_FOUND_WORDS = {\n no_library_ads: \"the brand has no ads in the library yet\",\n words_differ: \"no library ad says the same words\",\n not_live_together: \"it ran at a time the library has not read\",\n too_unlike: \"the closest library ad is not close enough\",\n} as const;\n\n/** Why the best family fits, in a few words: \"words 92% alike, same landing page, started 1 day apart\". */\nfunction evidenceWords(evidence: AdLibraryEvidence): string {\n const gap = evidence.startGapDays;\n return [\n `words ${Math.round(evidence.copy * 100)}% alike`,\n LANDING_WORDS[evidence.landing],\n gap === null ? null : gap === 0 ? \"started the same day\" : `started ${gap} day${gap === 1 ? \"\" : \"s\"} apart`,\n evidence.format === \"different\" ? \"different format\" : null,\n ]\n .filter((part): part is string => part !== null)\n .join(\", \");\n}\n\nconst titleOf = (concept: string | null, headline: string) => {\n const words = (concept ?? headline).trim();\n return words.length <= 120 ? words : `${words.slice(0, 119).trimEnd()}…`;\n};\n\ntype FoundChoice = Extract<AdLibraryChoicesData[\"creatives\"][number], { found: true }>;\n\n/** Why the best family fits, or why none does; null when Baker read neither. */\nfunction whyWords(choice: FoundChoice): string | null {\n if (choice.evidence) return evidenceWords(choice.evidence);\n return choice.notFoundReason ? NOT_FOUND_WORDS[choice.notFoundReason] : null;\n}\n\nfunction settledBy(choice: FoundChoice): \"by a person\" | \"by Baker\" | \"no\" {\n if (choice.chosen) return \"by a person\";\n return choice.familyId ? \"by Baker\" : \"no\";\n}\n\nfunction compactChoice(choice: FoundChoice) {\n const why = whyWords(choice);\n return {\n creative: choice.creativeKey,\n platform: choice.platform,\n status: choice.status,\n settled: settledBy(choice),\n ...(choice.familyId ? { familyId: choice.familyId } : {}),\n ...(why ? { why } : {}),\n families: choice.families.map((family) => ({\n familyId: family.familyId,\n title: titleOf(family.concept, family.headline),\n score: Math.round(family.score * 100) / 100,\n libraryAdId: family.adId,\n ...(family.firstSeen ? { started: family.firstSeen } : {}),\n })),\n };\n}\n\nexport function compactLibraryChoices(data: AdLibraryChoicesData) {\n return {\n creatives: data.creatives.map((choice) =>\n choice.found ? compactChoice(choice) : { creative: choice.creativeKey, status: \"unchecked\" },\n ),\n };\n}\n\nexport function libraryChoicesHints(data: AdLibraryChoicesData): string[] {\n const hints = [\n `families are best first (score 0-1). Show the person the candidates (open one with baker winning-ads content <libraryAdId> --platform <platform>), and once they say which it is, stage it: ${LINK_COMMAND} (or --not-in-library, or --auto to hand it back to Baker's reading, each with --name). It applies when the chat is published.`,\n ];\n if (data.creatives.some((choice) => choice.found && choice.chosen))\n hints.push(\"settled by a person: someone already chose this family; change it only if they ask.\");\n const unchecked = data.creatives.filter((choice) => !choice.found).map((choice) => choice.creativeKey);\n if (unchecked.length > 0)\n hints.push(\n `${unchecked.join(\", \")}: Baker has not checked these against the library. Use ${CREATIVE_KEY_WORDS}, on a platform the brand is in the library on (baker ads performance families → brand).`,\n );\n return hints;\n}\n\nexport function familyLinkInput(args: Args, chatId: string): Record<string, unknown> {\n const platform = enumValue(args.platform);\n const family = optionalString(args.family);\n const name = optionalString(args.name);\n return {\n chatId,\n creativeKey: optionalString(args.creative) ?? \"\",\n ...(platform ? { platform } : {}),\n ...(name ? { label: name } : {}),\n ...(family ? { familyId: family } : {}),\n ...(args[\"not-in-library\"] === true ? { notInLibrary: true } : {}),\n ...(args.auto === true ? { auto: true } : {}),\n };\n}\n\nconst PLATFORM_ARG = {\n type: \"string\",\n description: \"meta | google | linkedin | x | chatgpt (default: whichever has the creative)\",\n required: false,\n} as const;\n\nconst familiesChoicesCommand = report<typeof adLibraryChoicesRequestSchema, AdLibraryChoicesData>({\n name: \"choices\",\n schemaName: \"families.choices\",\n schemaDescription:\n \"The library families a launched creative may be, to settle one Baker could not (status ambiguous or likely; coverage.ambiguous in families): per creative (its libraryKey from baker ads performance creatives — mediaKey with --full — else its groupKey; several at once, up to 50) its status, whether it is settled and by whom, why the best family fits (words alike, landing page, start days apart) or why none does, and each candidate family best first — familyId, title (the library's concept), score 0-1, libraryAdId and the day it started. --full adds each family's picture or video. Read-only; settle one with families link.\",\n help: \"The families a creative may be. Example: baker ads performance families choices video:123,image:abc\",\n path: \"families/choices\",\n args: {\n creatives: {\n type: \"positional\",\n description:\n \"Creative keys (libraryKey from baker ads performance creatives, mediaKey with --full, else groupKey), space or comma separated\",\n required: true,\n },\n platform: PLATFORM_ARG,\n full: SCOPE_ARGS.full,\n },\n request: adLibraryChoicesRequestSchema,\n input: familyChoicesInput,\n compact: compactLibraryChoices,\n hints: libraryChoicesHints,\n});\n\nconst familiesLinkCommand = writeCommand({\n name: \"link\",\n schemaName: \"families.link\",\n schemaDescription:\n \"Stage which library family a launched creative is, as a person does from its card on the Ads screen: --family <familyId> (from families choices), --not-in-library, or --auto to drop a person's choice and hand it back to Baker's reading. --name (required) is the creative's name in creatives, which the person reviewing knows it by. Applies when the person publishes the chat; then families, hooks and the creatives' library readings count it there. A choice a person made meanwhile stays. Only on the person's word: never pick a family yourself from the score.\",\n help: 'Stage a creative\\'s library family.\\n\\nExamples:\\n baker ads performance families link video:123 --family 98765 --name \"Spring founder video\"\\n baker ads performance families link image:abc --not-in-library --name \"Rooftop photo\"\\n baker ads performance families link video:123 --auto --name \"Spring founder video\"',\n path: \"/api/ads/performance/families/link\",\n args: {\n creative: {\n type: \"positional\",\n description:\n \"The creative's key (libraryKey from baker ads performance creatives, mediaKey with --full, else groupKey)\",\n required: true,\n },\n family: { type: \"string\", description: \"The family it is: a familyId from families choices\", required: false },\n \"not-in-library\": { type: \"boolean\", description: \"It is not in the library\", required: false },\n auto: {\n type: \"boolean\",\n description: \"Drop a person's choice: Baker's own reading decides again\",\n required: false,\n },\n name: {\n type: \"string\",\n description:\n \"Required. What the creative is called (its name in creatives): the person reviewing knows it by that\",\n required: false,\n },\n platform: PLATFORM_ARG,\n },\n request: adLibraryLinkStageRequestSchema,\n input: familyLinkInput,\n});\n\nexport const familiesCommand = withWrites(familiesReadCommand, {\n choices: familiesChoicesCommand,\n link: familiesLinkCommand,\n});\n","/**\n * The pure half of `baker ads performance`: the compact view the agent reads by\n * default, what a report means that its rows alone don't say (hints), and the\n * refusal it cannot clear itself (error.fix).\n */\n\nimport {\n AD_PERFORMANCE_NOT_CONNECTED_MESSAGE,\n type AdAlert,\n type AdChangeImpactRow,\n type AdChangeRow,\n type AdCreativeRow,\n type AdDataStatus,\n type AdEntityRow,\n type AdMatureThrough,\n type AdMetrics,\n type AdPerformanceBreakdownData,\n type AdPerformanceChangesData,\n type AdPerformanceCreativesData,\n type AdPerformanceEntitiesData,\n type AdPerformanceEntityData,\n type AdPerformanceFunnelData,\n type AdPerformanceGoalsData,\n type AdPerformanceImpactData,\n type AdPerformanceOverviewData,\n type AdPerformancePlatform,\n type AdPerformanceTrackingData,\n type AdRatios,\n type AdReportWindow,\n adChangeWords,\n} from \"@baker/api/ads-performance\";\nimport { compactLibraryLink } from \"./library.ts\";\n\n// --- refusal ---\n\nexport type AdPerformanceRefusal =\n | { code: \"ADS_NOT_CONNECTED\"; fix: { action: \"ask_user\"; explanation: string } }\n | { code: \"VALIDATION_ERROR\"; fix: { action: \"retry_with_valid_values\"; explanation: string } };\n\n/**\n * \"No ad platform connected\" as the fix the agent relays. Matched on the\n * backend's own sentence (shared from `@baker/api/ads-performance`), because it\n * is a CONFLICT like any other. A `--currency` the store has no rate for (a\n * BAD_REQUEST, which the client reads as VALIDATION_ERROR) points at the\n * currencies it can show. Null for every other refusal.\n */\nexport function adPerformanceRefusal(code: string, message: string): AdPerformanceRefusal | null {\n if (code === \"VALIDATION_ERROR\" && message.startsWith(\"--currency \")) {\n return {\n code: \"VALIDATION_ERROR\",\n fix: {\n action: \"retry_with_valid_values\",\n explanation: \"run baker ads performance currency for the codes it can show (canShowIn), or pass native\",\n },\n };\n }\n if (code !== \"CONFLICT\" || !message.includes(AD_PERFORMANCE_NOT_CONNECTED_MESSAGE)) return null;\n return {\n code: \"ADS_NOT_CONNECTED\",\n fix: {\n action: \"ask_user\",\n explanation: \"Connect an ad platform in Integrations and select an ad account; history starts loading at once.\",\n },\n };\n}\n\n// --- rounding ---\n\n/** Money and counts to cents, small ratios to four significant digits: enough to decide, nothing to squint at. */\nexport function roundNumber(value: number): number {\n if (!Number.isFinite(value) || Number.isInteger(value)) return value;\n if (Math.abs(value) >= 1) return Math.round(value * 100) / 100;\n return Number(value.toPrecision(4));\n}\n\n/** Every number inside, rounded with `roundNumber`. */\nexport function roundDeep<T>(value: T): T {\n if (typeof value === \"number\") return roundNumber(value) as T;\n if (Array.isArray(value)) return value.map((item) => roundDeep(item)) as T;\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, roundDeep(item)])) as T;\n }\n return value;\n}\n\nfunction isoOrNull(millis: number | null): string | null {\n return millis === null ? null : new Date(millis).toISOString();\n}\n\n/** Drop `\"\"`, `null` and empty-list fields: an absent key reads the same and costs nothing. */\nfunction dropEmpty(record: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(record).filter(\n ([, value]) =>\n value !== \"\" && value !== null && value !== undefined && !(Array.isArray(value) && value.length === 0),\n ),\n );\n}\n\n// --- compact pieces ---\n\nconst CORE_METRICS = [\"spend\", \"impressions\", \"clicks\", \"linkClicks\", \"results\", \"resultValue\"] as const;\nconst CORE_RATIOS = [\"ctr\", \"cpc\", \"costPerResult\", \"resultValuePerSpend\"] as const;\nconst OPTIONAL_RATIOS = [\n \"impressionShare\",\n \"lostShareBudget\",\n \"lostShareRank\",\n \"topImpressionRate\",\n \"absoluteTopImpressionRate\",\n \"allConversionsPerConversion\",\n \"viewRate\",\n \"costPerView\",\n \"frequency\",\n] as const;\n/**\n * Summed daily reach reads as a reach and is not one: its only use is\n * `ratios.frequency`, as is the impressions sum beside it. The two other\n * \"measured\" sums are only the denominators of the top-of-page rates and of\n * `allConversionsPerConversion`.\n */\nconst HIDDEN_METRICS: ReadonlySet<string> = new Set([\n \"reach\",\n \"reachMeasuredImpressions\",\n \"searchTopMeasuredImpressions\",\n \"allConversionsMeasuredConversions\",\n]);\n\n/** The metrics that decide most questions, plus any other that is not zero. */\nexport function compactMetrics(metrics: AdMetrics): Record<string, number> {\n const out: Record<string, number> = {};\n for (const key of CORE_METRICS) out[key] = roundNumber(metrics[key]);\n for (const [key, value] of Object.entries(metrics) as Array<[keyof AdMetrics, number]>) {\n if (!(key in out) && value !== 0 && !HIDDEN_METRICS.has(key)) out[key] = roundNumber(value);\n }\n return out;\n}\n\n/** The four ratios most questions turn on, plus impression share where a search platform has it. */\nexport function compactRatios(ratios: AdRatios): Record<string, number | null> {\n const out: Record<string, number | null> = {};\n for (const key of CORE_RATIOS) out[key] = ratios[key] === null ? null : roundNumber(ratios[key]);\n for (const key of OPTIONAL_RATIOS) {\n const value = ratios[key];\n if (value !== null) out[key] = roundNumber(value);\n }\n return out;\n}\n\n/** \"Spring › Spring – broad › Spring ad\": where an ad set, ad or keyword sits; null for a campaign. */\nexport function entityPath(\n row: Pick<AdEntityRow, \"level\" | \"name\" | \"entityId\" | \"campaignName\" | \"campaignId\" | \"adGroupName\" | \"adGroupId\">,\n): string | null {\n if (row.level === \"campaign\") return null;\n const parts = [row.campaignName || row.campaignId];\n if (row.level !== \"ad_group\") parts.push(row.adGroupName || row.adGroupId);\n return [...parts.filter(Boolean), row.name || row.entityId].join(\" › \");\n}\n\nexport function compactEntityRow(row: AdEntityRow): Record<string, unknown> {\n const childLevel = row.level === \"ad\" || row.level === \"keyword\";\n return {\n ...dropEmpty({\n platform: row.platform,\n adAccountId: row.adAccountId,\n level: row.level,\n entityId: row.entityId,\n name: row.name,\n campaignId: row.level === \"campaign\" ? \"\" : row.campaignId,\n campaignName: row.level === \"campaign\" ? \"\" : row.campaignName,\n adGroupId: childLevel ? row.adGroupId : \"\",\n adGroupName: childLevel ? row.adGroupName : \"\",\n status: row.status,\n objective: row.objective,\n bidStrategy: row.bidStrategy,\n headline: row.headline,\n destinationUrl: row.destinationUrl,\n currency: row.currency,\n budgetDaily: row.budgetDaily === null ? null : roundNumber(row.budgetDaily),\n budgetLifetime: row.budgetLifetime === null ? null : roundNumber(row.budgetLifetime),\n }),\n metrics: compactMetrics(row.metrics),\n ratios: compactRatios(row.ratios),\n ...(entityPath(row) ? { path: entityPath(row) } : {}),\n firstDelivery: row.firstDelivery,\n lastDelivery: row.lastDelivery,\n ...(row.beforeHistory ? { beforeHistory: true } : {}),\n peer: roundDeep(row.peer),\n ...compactSearchParts(row),\n };\n}\n\n/** A Google campaign's type and segment, its change against the period before, and who stopped it. */\nfunction compactSearchParts(row: AdEntityRow): Record<string, unknown> {\n return {\n ...dropEmpty({ campaignKind: row.campaignKind, segment: row.segment }),\n ...(row.segmentMixed ? { segmentMixed: true } : {}),\n ...(row.comparison ? { change: compactChangeOf(row.comparison) } : {}),\n ...(row.stop ? { stopped: compactStop(row.stop) } : {}),\n };\n}\n\nfunction compactStop(stop: NonNullable<AdEntityRow[\"stop\"]>): Record<string, unknown> {\n const by = stop.actorKind === \"baker\" ? `Baker (${stop.chatTitle || \"a chat\"})` : stop.actor || stop.actorKind;\n return dropEmpty({\n at: new Date(stop.changedAt).toISOString(),\n how: stop.kind === \"removed\" ? \"removed\" : stop.newValue,\n by,\n });\n}\n\n/** Against the period before (settled days): what it spent then, and every change that is known, rounded. */\nfunction compactChangeOf(comparison: NonNullable<AdEntityRow[\"comparison\"]>): Record<string, number> {\n const out: Record<string, number> = { previousSpend: roundNumber(comparison.previous.spend) };\n for (const [key, value] of Object.entries(comparison.deltas)) if (value !== null) out[key] = roundNumber(value);\n return out;\n}\n\n/**\n * A change as the dashboard says it (`summary`, `adChangeWords`), amounts in\n * the ad account's own currency. Raw values stay only while they are short:\n * Meta's targeting and ad copy come as JSON, read here as `fullText`, whole with `--full`.\n */\nexport function compactChange(row: AdChangeRow): Record<string, unknown> {\n const words = adChangeWords(row);\n const raw = words.full === null ? { oldValue: row.oldValue, newValue: row.newValue } : {};\n return dropEmpty({\n changedAt: new Date(row.changedAt).toISOString(),\n platform: row.platform,\n adAccountId: row.adAccountId,\n level: row.level,\n entityId: row.entityId,\n entityName: row.entityName,\n campaignId: row.level === \"campaign\" || row.campaignId === row.entityId ? \"\" : row.campaignId,\n campaignName: row.campaignName,\n kind: row.kind,\n field: row.field,\n summary: words.summary,\n fullText: words.full ?? \"\",\n ...raw,\n valueCurrency: row.valueCurrency,\n actor: row.actor,\n actorKind: row.actorKind,\n source: row.source,\n chatId: row.chatId,\n chatTitle: row.chatTitle,\n platformCheck: row.platformCheck,\n });\n}\n\nexport function compactAlert(alert: AdAlert): Record<string, unknown> {\n return dropEmpty({\n severity: alert.severity,\n platform: alert.platform,\n level: alert.level,\n entityId: alert.entityId,\n entityName: alert.entityName,\n title: alert.title,\n message: alert.message,\n action: alert.action,\n moneyAtStake: alert.moneyAtStake === null ? null : roundNumber(alert.moneyAtStake),\n currency: alert.moneyAtStake === null ? \"\" : alert.currency,\n annotation: alert.annotation,\n });\n}\n\nfunction compactDataStatus(status: AdDataStatus): Record<string, unknown> {\n return {\n historyLoading: status.historyLoading,\n platforms: status.platforms.map((platform) =>\n dropEmpty({\n platform: platform.platform,\n connected: platform.connected,\n syncedAt: isoOrNull(platform.lastSuccessAt),\n error: platform.error,\n accounts: platform.accounts\n .filter((account) => account.selected)\n .map((account) =>\n dropEmpty({\n adAccountId: account.adAccountId,\n name: account.name,\n currency: account.currency,\n historyFrom: account.historyFrom,\n newestDate: account.newestDate,\n historyComplete: account.backfillComplete,\n error: account.error,\n adsInManyAdGroups: account.adsInManyAdGroups,\n }),\n ),\n }),\n ),\n };\n}\n\n// --- compact reports ---\n\nexport function compactOverview(data: AdPerformanceOverviewData): Record<string, unknown> {\n return {\n window: data.window,\n platforms: data.platforms.map((score) => ({\n platform: score.platform,\n currency: score.currency,\n activeCampaigns: score.activeCampaigns,\n matureThrough: score.matureThrough,\n metrics: compactMetrics(score.metrics),\n ratios: compactRatios(score.ratios),\n comparison:\n score.comparison === null\n ? null\n : {\n current: score.comparison.current,\n previous: score.comparison.previous,\n deltas: roundDeep(score.comparison.deltas),\n },\n })),\n totalsByCurrency: data.totalsByCurrency.map((total) => ({\n currency: total.currency,\n metrics: compactMetrics(total.metrics),\n ratios: compactRatios(total.ratios),\n })),\n trend: data.trend.map((point) => ({\n bucket: point.bucket,\n platform: point.platform,\n currency: point.currency,\n spend: roundNumber(point.metrics.spend),\n results: roundNumber(point.metrics.results),\n costPerResult: point.ratios.costPerResult === null ? null : roundNumber(point.ratios.costPerResult),\n mature: point.mature,\n })),\n goals: data.goals.map((goal) => ({ platform: goal.platform, actions: goal.actions, countValue: goal.countValue })),\n resultNoun: { singular: data.resultNoun.singular, plural: data.resultNoun.plural },\n openAlerts: data.openAlerts,\n topAlerts: data.topAlerts.map(compactAlert),\n dataStatus: compactDataStatus(data.dataStatus),\n };\n}\n\nexport function compactEntities(data: AdPerformanceEntitiesData): Record<string, unknown> {\n return {\n window: data.window,\n level: data.level,\n totalRows: data.totalRows,\n spentRows: data.spentRows,\n stoppedRows: data.stoppedRows,\n rows: data.rows.map(compactEntityRow),\n };\n}\n\nexport function compactEntity(data: AdPerformanceEntityData): Record<string, unknown> {\n return {\n window: data.window,\n wholeRun: data.wholeRun,\n matureThrough: data.matureThrough,\n verdict: roundDeep(data.verdict),\n entity: data.entity === null ? null : compactEntityRow(data.entity),\n daily: data.daily.map((day) => ({\n date: day.date,\n spend: roundNumber(day.metrics.spend),\n impressions: day.metrics.impressions,\n linkClicks: day.metrics.linkClicks,\n results: roundNumber(day.metrics.results),\n costPerResult: day.ratios.costPerResult === null ? null : roundNumber(day.ratios.costPerResult),\n mature: day.mature,\n })),\n changes: data.changes.map(compactChange),\n children:\n data.children === null\n ? null\n : {\n level: data.children.level,\n totalRows: data.children.totalRows,\n rows: data.children.rows.map(compactEntityRow),\n },\n openAlerts: data.openAlerts.map(compactAlert),\n };\n}\n\nexport function compactChanges(data: AdPerformanceChangesData): Record<string, unknown> {\n return { window: data.window, totalRows: data.totalRows, changes: data.changes.map(compactChange) };\n}\n\nexport function changesHints(data: AdPerformanceChangesData, request: { offset: number }): string[] {\n const paging = pagingHint(data.totalRows, request.offset, data.changes.length);\n return paging === null ? [] : [paging];\n}\n\n/** How many of a folded line's edits the compact output names; `--full` has them all (`editValues`). */\nconst EDIT_SAMPLE = 5;\n\nfunction compactImpactRow(row: AdChangeImpactRow): Record<string, unknown> {\n return {\n ...compactChange({ ...row, campaignName: \"\" }),\n currency: row.currency,\n verdict: row.verdict,\n effect: row.effect === null ? null : roundNumber(row.effect),\n basis: row.basis,\n reason: row.reason,\n ...(row.confounded ? { confounded: true } : {}),\n ...(row.edits > 1 ? { edits: row.edits, editSample: row.editValues.slice(0, EDIT_SAMPLE) } : {}),\n beforeDays: row.beforeDays,\n afterDays: row.afterDays,\n before: roundDeep(row.before),\n after: roundDeep(row.after),\n };\n}\n\nexport function compactImpact(data: AdPerformanceImpactData): Record<string, unknown> {\n return {\n window: data.window,\n impactDays: data.impactDays,\n totalRows: data.totalRows,\n changes: data.changes.map(compactImpactRow),\n };\n}\n\n/** The company's own creative a reported one is: its slug for `baker creatives`, and the version that runs. */\nexport function compactMadeInBaker(made: AdCreativeRow[\"madeInBaker\"]): Record<string, unknown> | null {\n if (!made) return null;\n return {\n slug: made.slug,\n title: made.title,\n ...(made.versionNumber !== null ? { version: made.versionNumber } : {}),\n ...(made.confidence === \"likely\" ? { likely: true } : {}),\n };\n}\n\nfunction compactCreativeRow(row: AdCreativeRow): Record<string, unknown> {\n return {\n ...dropEmpty({\n groupKey: row.groupKey,\n libraryKey: row.mediaKey === row.groupKey ? \"\" : row.mediaKey,\n platforms: row.platforms,\n adAccountId: row.adAccountId,\n topAdId: row.topAdId,\n name: row.name,\n headline: row.headline,\n creativeFormat: row.creativeFormat,\n destinationUrl: row.destinationUrl,\n currency: row.currency,\n }),\n ads: row.ads,\n activeAds: row.activeAds,\n metrics: compactMetrics(row.metrics),\n ratios: compactRatios(row.ratios),\n peerStanding: row.peerStanding,\n peerIndex: row.peerIndex === null ? null : roundNumber(row.peerIndex),\n peerBasis: row.peerBasis,\n expected: roundNumber(row.peerBasis === \"link_clicks\" ? row.expectedLinkClicks : row.expectedResults),\n firstDelivery: row.firstDelivery,\n lastDelivery: row.lastDelivery,\n library: compactLibraryLink(row.library),\n madeInBaker: compactMadeInBaker(row.madeInBaker),\n };\n}\n\nexport function compactCreatives(data: AdPerformanceCreativesData): Record<string, unknown> {\n return { window: data.window, groupBy: data.groupBy, creatives: data.creatives.map(compactCreativeRow) };\n}\n\nexport function compactBreakdown(data: AdPerformanceBreakdownData): Record<string, unknown> {\n return {\n window: data.window,\n dimension: data.dimension,\n rows: data.rows.map((row) => ({\n platform: row.platform,\n value: row.value,\n currency: row.currency,\n spend: roundNumber(row.spend),\n impressions: row.impressions,\n clicks: row.clicks,\n results: roundNumber(row.results),\n ...(row.resultValue > 0 ? { resultValue: roundNumber(row.resultValue) } : {}),\n spendShare: row.spendShare === null ? null : roundNumber(row.spendShare),\n resultShare: row.resultShare === null ? null : roundNumber(row.resultShare),\n costPerResult: row.costPerResult === null ? null : roundNumber(row.costPerResult),\n ctr: row.ctr === null ? null : roundNumber(row.ctr),\n })),\n };\n}\n\nexport function compactStatus(status: AdDataStatus): Record<string, unknown> {\n return compactDataStatus(status);\n}\n\n// --- hints ---\n\nconst PLATFORM_LABEL: Record<AdPerformancePlatform, string> = {\n meta: \"Meta\",\n google: \"Google Ads\",\n linkedin: \"LinkedIn\",\n x: \"X\",\n chatgpt: \"ChatGPT Ads\",\n};\n\nexport function platformLabel(platform: string): string {\n return PLATFORM_LABEL[platform as AdPerformancePlatform] ?? platform;\n}\n\nfunction historyLoadingHint(status: AdDataStatus): string | null {\n if (!status.historyLoading) return null;\n const loading = status.platforms.flatMap((platform) =>\n platform.accounts\n .filter((account) => account.selected && !account.backfillComplete)\n .map(\n (account) =>\n `${account.name || account.adAccountId} (${platformLabel(platform.platform)}${account.historyFrom ? `, stored from ${account.historyFrom}` : \"\"})`,\n ),\n );\n const which = loading.length > 0 ? loading.join(\", \") : \"some ad accounts\";\n return `History is still loading for ${which}; older periods are incomplete. Say so before comparing them, or read a recent window.`;\n}\n\nconst NO_GOALS_HINT =\n \"No result goals are set, so results are each platform's headline conversions. Run `baker ads performance goals` to see every conversion action each platform reported.\";\n\n/** How to name results to the person: the company's own word, or \"results\" when the count mixes goals with every conversion. */\nfunction resultNounHint(noun: AdPerformanceOverviewData[\"resultNoun\"]): string | null {\n if (noun.source === \"company\")\n return `This company calls a result a \"${noun.singular}\": say \"${noun.plural}\" and \"cost per ${noun.singular}\", as its Ads screens do.`;\n if (noun.source === \"mixed\")\n return 'Some ad accounts in view have no goal and count every conversion, or the goals count different things: say \"results\", never \"leads\", for these totals.';\n return null;\n}\n\nexport function overviewHints(data: AdPerformanceOverviewData): string[] {\n const hints: string[] = [];\n const loading = historyLoadingHint(data.dataStatus);\n if (loading !== null) hints.push(loading);\n if (data.goals.length === 0 && data.platforms.length > 0) hints.push(NO_GOALS_HINT);\n const noun = resultNounHint(data.resultNoun);\n if (noun !== null) hints.push(noun);\n const inView = new Set(data.platforms.map((score) => score.platform));\n const unsettled = data.matureThrough.filter((mature) => inView.has(mature.platform) && mature.date < data.window.to);\n if (unsettled.length > 0) {\n const through = unsettled.map((mature) => `${platformLabel(mature.platform)} through ${mature.date}`).join(\", \");\n hints.push(\n `Results after these days are still settling and will rise: ${through}. Compare only settled days (comparison already does); never judge the last days against older ones.`,\n );\n }\n if (data.totalsByCurrency.length > 1) {\n hints.push(\"Spend is in more than one currency. Report each currency on its own line; never add them up.\");\n }\n return hints;\n}\n\n/** The window's last days, per platform present, that have not settled yet — the backend's own settled days. */\nfunction settlingHint(\n window: AdReportWindow,\n platforms: Iterable<string>,\n matureThrough: readonly AdMatureThrough[],\n): string | null {\n const notes: string[] = [];\n const present = new Set(platforms);\n for (const mature of matureThrough) {\n if (present.has(mature.platform) && window.to > mature.date)\n notes.push(`${platformLabel(mature.platform)} after ${mature.date}`);\n }\n if (notes.length === 0) return null;\n return `Results for the window's last days are still settling (${notes.join(\", \")}), so cost per result there reads high. Compare only settled days.`;\n}\n\n/** \"Showing 1-50 of 84\": the next page's --offset, when more rows match than this page holds. */\nexport function pagingHint(totalRows: number, offset: number, rows: number): string | null {\n const shown = offset + rows;\n if (totalRows <= shown) return null;\n return `Showing ${offset + 1}-${shown} of ${totalRows}. Read the next page with --offset ${shown}.`;\n}\n\nexport function entitiesHints(data: AdPerformanceEntitiesData, request: { offset: number }): string[] {\n const hints: string[] = [];\n const settling = settlingHint(\n data.window,\n data.rows.map((row) => row.platform),\n data.matureThrough,\n );\n if (settling !== null) hints.push(settling);\n const paging = pagingHint(data.totalRows, request.offset, data.rows.length);\n if (paging !== null) hints.push(paging);\n if (new Set(data.rows.map((row) => row.currency)).size > 1) {\n hints.push(\"Rows are in more than one currency. Never add or rank money across currencies.\");\n }\n const levels = new Set(data.rows.map((row) => row.level));\n if (levels.has(\"campaign\"))\n hints.push(\n \"To read what is inside one campaign: --campaign-ids <entityId> --level ad_group; inside one ad set: --ad-group-ids <entityId> --level ad. Say where a row sits by its path.\",\n );\n else if (levels.has(\"ad_group\"))\n hints.push(\"To read the ads inside one ad set: --ad-group-ids <entityId> --level ad.\");\n return hints;\n}\n\nexport function entityHints(\n data: AdPerformanceEntityData,\n request: { entityId: string; level: string; currency?: string },\n): string[] {\n if (data.entity === null) {\n return [\n `No ${request.level} with id ${request.entityId} was found on that platform. Check the id, platform and level with \\`baker ads performance entities --level ${request.level} --include-idle\\`.`,\n ];\n }\n const verdict = data.verdict;\n if (verdict === null) return [];\n if (!verdict.applies) return verdict.summary ? [verdict.summary] : [];\n const hints: string[] = [];\n if (!verdict.enoughData) {\n hints.push(\n `Not enough settled data to judge it yet (${verdict.enoughDataReason}). Wait before changing it; any change now is a guess.`,\n );\n }\n if (verdict.learning) hints.push(`It is still learning (${verdict.learningReason}). A change now restarts learning.`);\n const step = verdict.safeBudgetStep;\n if (step.waitDays > 0) {\n hints.push(`Wait ${step.waitDays} more day(s) before changing its budget: ${step.reason}`);\n } else if (step.suggestedDailyBudget !== null) {\n // A budget is written in the ad account's own currency; only a native read is sure to show it in that.\n hints.push(\n request.currency === \"native\"\n ? `A budget step up to ${step.maxIncreasePct}% (about ${roundNumber(step.suggestedDailyBudget)} ${data.entity.currency} a day) should not reset learning.`\n : `A budget step up to ${step.maxIncreasePct}% should not reset learning. Amounts here may be converted out of the ad account's own currency, which a budget change is written in: re-run with --currency native for the daily amount to stage.`,\n );\n }\n return hints;\n}\n\nexport function impactHints(data: AdPerformanceImpactData): string[] {\n const hints: string[] = [];\n const tooEarly = data.changes.filter((row) => row.verdict === \"too_early\");\n if (tooEarly.length > 0) {\n hints.push(\n `${tooEarly.length} change(s) are too early to judge: their days after the change have not settled yet (each row's \\`reason\\` says when to look again). Do not call them a win or a loss yet.`,\n );\n }\n if (data.changes.some((row) => row.confounded)) {\n hints.push(\n \"Changes marked confounded overlap another change on the same entity; their effect cannot be told apart.\",\n );\n }\n return hints;\n}\n\nexport function creativesHints(\n data: AdPerformanceCreativesData,\n request: { groupBy: \"creative\" | \"ad\"; platforms?: readonly string[] },\n): string[] {\n const hints: string[] = [];\n const asked = request.platforms ?? data.matureThrough.map((mature) => mature.platform);\n if (\n request.groupBy === \"creative\" &&\n asked.includes(\"google\") &&\n !data.creatives.some((row) => row.platforms.includes(\"google\"))\n )\n hints.push(\n \"No Google Ads row: text-only ads (Search) have no picture or video, so grouping by creative leaves them out. List them with --group-by ad.\",\n );\n const settling = settlingHint(\n data.window,\n data.creatives.flatMap((row) => row.platforms),\n data.matureThrough,\n );\n if (settling !== null) hints.push(settling);\n if (data.creatives.some((row) => row.peerStanding !== \"too_little_data\")) {\n hints.push(\n \"peerIndex compares each creative with its ad-group siblings (1 = like them, 1.3 = 30% better), shrunk toward 1 when the data is thin. Rank by it, not by raw cost per result.\",\n );\n }\n return hints;\n}\n\n/** The platforms whose sync reads each split (the backend adapters' `breakdowns`). */\nconst BREAKDOWN_PLATFORMS: Record<AdPerformanceBreakdownData[\"dimension\"], AdPerformancePlatform[]> = {\n placement: [\"meta\", \"google\"],\n country: [\"meta\", \"google\"],\n device: [\"meta\", \"google\"],\n audience_segment: [\"meta\"],\n age: [\"meta\"],\n gender: [\"meta\"],\n};\n\nexport function breakdownHints(\n data: AdPerformanceBreakdownData,\n request: { dimension: AdPerformanceBreakdownData[\"dimension\"]; platforms?: readonly string[] },\n): string[] {\n if (data.rows.length > 0) return [];\n const reporting = BREAKDOWN_PLATFORMS[request.dimension];\n const names = reporting.map(platformLabel).join(\" and \");\n const asked = request.platforms;\n const outside =\n asked !== undefined && !asked.some((platform) => reporting.includes(platform as AdPerformancePlatform));\n return [\n `Nothing is split by ${request.dimension} here. Only ${names} ${reporting.length === 1 ? \"reports\" : \"report\"} ${request.dimension}${outside ? `: read it with --platforms ${reporting.join(\",\")}` : \"\"}.`,\n ];\n}\n\n/** The staged write that adds tracking parameters, per platform; null where Baker has none. */\nconst TRACKING_FIX: Record<AdPerformancePlatform, string | null> = {\n meta: '`baker ads meta ads retag <ad-id> --set \"…\"` (see ads-meta.md)',\n google:\n '`baker ads google campaigns update <campaign-id> --customer-id <id> --final-url-suffix \"…\"` (read `baker ads google url-options` first)',\n linkedin: '`baker ads linkedin account url-params --param \"…\"`',\n x: null,\n chatgpt: null,\n};\n\n/** Below this share of paid visits carrying a campaign id, the funnel and landing reads undercount. */\nconst LOW_CAMPAIGN_ID_SHARE = 0.8;\nconst MIN_PAID_SESSIONS = 20;\n\n/** The site reads keep 400 days of visits; a longer window was clipped, and the answer says which days it covers. */\nexport function clippedWindowHint(data: { window: AdReportWindow; windowClipped: boolean }): string[] {\n return data.windowClipped\n ? [\n `Visits are kept for 400 days, so this covers ${data.window.from} to ${data.window.to} (${data.window.days} days), not the longer window asked for.`,\n ]\n : [];\n}\n\nexport function trackingHints(data: AdPerformanceTrackingData): string[] {\n const hints: string[] = [...clippedWindowHint(data)];\n for (const row of data.rows) {\n const untagged = row.activeAdsWithoutParams > 0;\n const share = row.campaignIdShare;\n const lowShare = share !== null && row.paidSessions >= MIN_PAID_SESSIONS && share < LOW_CAMPAIGN_ID_SHARE;\n if (!untagged && !lowShare) continue;\n const problem = untagged\n ? `${row.activeAdsWithoutParams} of the ${row.activeAds} ${platformLabel(row.platform)} ads that spent in this window send no tracking parameters`\n : `only ${Math.round((share ?? 0) * 100)}% of ${platformLabel(row.platform)} paid visits carry a campaign id`;\n const fix = TRACKING_FIX[row.platform as AdPerformancePlatform];\n hints.push(\n fix\n ? `${problem}. Stage the fix with ${fix}; it applies when the chat is published.`\n : `${problem}. Baker cannot set them on ${platformLabel(row.platform)} yet; the user adds them in the platform's ads manager.`,\n );\n }\n return hints;\n}\n\nexport function funnelHints(data: AdPerformanceFunnelData): string[] {\n const leaky = data.rows.filter(\n (row) => row.clickToSession !== null && row.clickToSession < 0.6 && row.linkClicks >= 50,\n );\n if (leaky.length === 0) return clippedWindowHint(data);\n return [\n ...clippedWindowHint(data),\n `${leaky.length} row(s) turn fewer than 6 in 10 link clicks into visits: clicks are not arriving, or arriving without tracking. Check \\`baker ads performance tracking\\`.`,\n ];\n}\n\nexport function goalsHints(data: AdPerformanceGoalsData): string[] {\n if (data.goals.length > 0) return [];\n return [\"No result goals are set, so every report counts each platform's headline conversions as results.\"];\n}\n\n/** Ads whose numbers came from two ad groups or campaigns: one ad's numbers are not one ad group's. */\nfunction splitAdsHints(status: AdDataStatus): string[] {\n return status.platforms.flatMap((platform) =>\n platform.accounts\n .filter((account) => account.selected && account.adsInManyAdGroups.length > 0)\n .map((account) => {\n const count = account.adsInManyAdGroups.length;\n return `${count} ${platformLabel(platform.platform)} ${count === 1 ? \"ad\" : \"ads\"} in ${account.name || account.adAccountId} ran in more than one ad group or campaign in the last 30 days (adsInManyAdGroups): Baker adds each one's numbers together under its live ad group. Say so before judging an ad group by those ads.`;\n }),\n );\n}\n\nexport function statusHints(status: AdDataStatus): string[] {\n const hints: string[] = [];\n const loading = historyLoadingHint(status);\n if (loading !== null) hints.push(loading);\n for (const platform of status.platforms) {\n if (platform.connected && platform.error)\n hints.push(`${platformLabel(platform.platform)} last sync failed: ${platform.error}`);\n }\n hints.push(...splitAdsHints(status));\n return hints;\n}\n","/**\n * `baker ads performance accounts` — the Summary's accounts table: per ad\n * account its period, its change against the days before, its target and\n * where it stands, and its cost per result week by week (month by month at\n * `--grain month`) (`convex/adPerformance/accountsReport.ts`). Read-only.\n */\n\nimport {\n AD_ACCOUNTS_GRANULARITIES,\n type AdPerformanceAccountsData,\n adPerformanceAccountsRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { enumValue, SCOPE_ARGS, scopeInput } from \"./args.ts\";\nimport { roundNumber } from \"./report.ts\";\nimport { report, STORE_NOTE } from \"./reportCommand.ts\";\n\nfunction percent(share: number | null): string | null {\n if (share === null) return null;\n return `${share >= 0 ? \"+\" : \"−\"}${Math.round(Math.abs(share) * 100)}%`;\n}\n\n/** The line's name: weeks at the day and week grains, months at the month grain. */\nfunction seriesKey(data: AdPerformanceAccountsData): \"weekly\" | \"monthly\" {\n return data.granularity === \"month\" ? \"monthly\" : \"weekly\";\n}\n\nexport function compactAccounts(data: AdPerformanceAccountsData): Record<string, unknown> {\n return {\n headline: data.headline,\n window: data.window,\n accounts: data.accounts.map((row) => ({\n platform: row.platform,\n adAccountId: row.adAccountId,\n name: row.name,\n currency: row.currency,\n spend: Math.round(row.spend),\n results: roundNumber(row.results),\n costPerResult: row.costPerResult === null ? null : roundNumber(row.costPerResult),\n ...(row.change\n ? {\n change: {\n spend: percent(row.change.spend),\n results: percent(row.change.results),\n costPerResult: percent(row.change.costPerResult),\n },\n }\n : {}),\n ...(row.target\n ? {\n target: {\n value: row.target.value,\n metric: row.target.metric,\n ...(row.target.currency && row.target.currency !== row.currency ? { currency: row.target.currency } : {}),\n from: row.target.source,\n },\n }\n : {}),\n status: row.status,\n ...(row.bySearch.length > 0 ? { bySearch: row.bySearch } : {}),\n [seriesKey(data)]: row.series.map((bucket) =>\n bucket.costPerResult === null ? null : roundNumber(bucket.costPerResult),\n ),\n })),\n ...(data.notSpending.length > 0 ? { notSpending: data.notSpending.map((account) => account.name) } : {}),\n };\n}\n\nexport function accountsHints(data: AdPerformanceAccountsData): string[] {\n const unit = data.granularity === \"month\" ? \"month\" : \"week\";\n const hints = [\n `Tell the person the headline as it is. ${seriesKey(data)} is cost per result ${unit} by ${unit}, oldest first, the first and last ${unit} maybe partial.`,\n ];\n if (data.granularity !== \"day\")\n hints.push(\n `change compares whole settled ${unit}s only, as the dashboard's table does at this grain, so it can differ from the day grain's.`,\n );\n const off = data.accounts.find((row) => row.status === \"above_target\" || row.status === \"below_target\");\n if (off)\n hints.push(\n `To see what drives ${off.name}: baker ads performance entities --ad-account-ids ${off.adAccountId} --platforms ${off.platform}, then baker ads performance attention for what to fix.`,\n );\n if (data.accounts.some((row) => row.bySearch.length > 0))\n hints.push(\n \"bySearch: a Google account judged by kind of search (its Search targets are split): report those verdicts, as the dashboard does.\",\n );\n return hints;\n}\n\nconst ACCOUNTS_ARGS = {\n ...SCOPE_ARGS,\n grain: {\n type: \"string\",\n description: `${AD_ACCOUNTS_GRANULARITIES.join(\", \")}: the grain the dashboard's accounts table is read at (default day). The change compares whole settled days, weeks or months; the line is weekly, or monthly at month`,\n required: false,\n },\n} as const;\n\nexport const accountsCommand = report<typeof adPerformanceAccountsRequestSchema, AdPerformanceAccountsData>({\n name: \"accounts\",\n schemaName: \"accounts\",\n schemaDescription: `Per ad account, the Summary's accounts table: spend, results and cost per result for the window, change against as many days before, the target that judges it (from: account, platform, segment or company) and its status (on_target, above_target, below_target, not_enough_data, no_target), its cost per result week by week (month by month with --grain month), and the accounts that did not spend. Leads with a headline. Default the last 30 complete days at the day grain; --grain week or month reads the table as the dashboard does at that grain (the change then compares whole settled weeks or months). ${STORE_NOTE}`,\n help: \"Each ad account against its target. Example: baker ads performance accounts --days 90 --grain week\",\n path: \"accounts\",\n args: ACCOUNTS_ARGS,\n request: adPerformanceAccountsRequestSchema,\n input: (args) => ({ ...scopeInput(args), granularity: enumValue(args.grain) }),\n compact: compactAccounts,\n hints: accountsHints,\n});\n","/**\n * `baker ads performance targets | budget-recommendations` — the company's ad\n * targets per ad account and event with the period's numbers against them,\n * what its live ad groups optimise for, and per campaign or ad group whether\n * to scale, hold, cut or pause against its target\n * (`convex/adPerformance/targetReports.ts`). Changing a target or what counts\n * as a result is `targets set` / `goals set` (`goalWrites.ts`), staged on the\n * chat; no recommendation changes a budget — a budget change is staged with\n * `baker ads <platform>` like any other.\n */\n\nimport {\n type AdGoalNumbers,\n type AdGoalsData,\n type AdPerformanceBudgetRecommendationsData,\n type AdPerformanceTargetsData,\n adPerformanceBudgetRecommendationsRequestSchema,\n adPerformanceTargetsRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { type ArgsDef, defineCommand } from \"citty\";\nimport type { z } from \"zod\";\nimport { optionalOwnChatId } from \"../../../env.ts\";\nimport { writeJson } from \"../../../output.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { commaList, emptyFlagIssues, enumValue, optionalNumber, SCOPE_ARGS } from \"./args.ts\";\nimport { roundDeep } from \"./report.ts\";\nimport { failInvalid, failRead, postRead } from \"./reportCommand.ts\";\n\ntype Args = Record<string, unknown>;\n\n// --- pure: compact views and hints ---\n\nconst HOW_TO_CHANGE =\n \"To change a target, ask the person what the business can afford, then stage it: baker ads performance targets set (per event with --event on Meta and LinkedIn, per ad account, or --company). What counts as a result: baker ads performance goals set. Both apply when the person publishes this chat. How sensitive the cost-rise and overspend alerts are (alerts): baker ads performance targets alert-lines, also staged.\";\n\nconst round = (value: number | null) => (value === null ? null : Math.round(value * 100) / 100);\n\nfunction compactNumbers(row: AdGoalNumbers) {\n return {\n spend: round(row.spend),\n results: round(row.results),\n ...(row.target?.metric === \"roas\" ? { roas: round(row.roas) } : { costPerResult: round(row.costPerResult) }),\n target: row.target ? { value: round(row.target.value), metric: row.target.metric, from: row.target.source } : null,\n status: row.status,\n };\n}\n\ntype GoalAccount = AdGoalsData[\"accounts\"][number];\n\n/** No spend and no event over the period: nothing to judge, only a target to keep. */\nfunction idle(account: GoalAccount): boolean {\n return (account.total.spend ?? 0) === 0 && account.events.length === 0;\n}\n\n/** Where an account stands, the way the dashboard judges it: by its Search targets when they are split. */\nfunction standing(account: GoalAccount): \"on_target\" | \"above_target\" | \"below_target\" | \"not_judged\" {\n const statuses = account.searchSplit.length > 0 ? account.searchSplit.map((e) => e.status) : [account.total.status];\n if (statuses.includes(\"above_target\")) return \"above_target\";\n if (statuses.includes(\"below_target\")) return \"below_target\";\n return statuses.includes(\"on_target\") ? \"on_target\" : \"not_judged\";\n}\n\nconst STANDING_WORDS = {\n on_target: \"on target\",\n above_target: \"above target\",\n below_target: \"below target\",\n not_judged: \"not judged yet\",\n} as const;\n\n/** \"2 ad accounts spent in the last 30 days: 1 on target, 1 above target. 1 did not spend.\" */\nexport function targetsHeadline(goals: AdGoalsData): string {\n const spending = goals.accounts.filter((account) => !idle(account));\n const quiet = goals.accounts.length - spending.length;\n const counts = new Map<keyof typeof STANDING_WORDS, number>();\n for (const account of spending) counts.set(standing(account), (counts.get(standing(account)) ?? 0) + 1);\n const parts = (Object.keys(STANDING_WORDS) as Array<keyof typeof STANDING_WORDS>)\n .filter((key) => counts.has(key))\n .map((key) => `${counts.get(key)} ${STANDING_WORDS[key]}`);\n const lead = `${spending.length} ad account${spending.length === 1 ? \"\" : \"s\"} spent in the last ${goals.window.days} days`;\n return `${lead}${parts.length > 0 ? `: ${parts.join(\", \")}` : \"\"}.${quiet > 0 ? ` ${quiet} did not spend.` : \"\"}`;\n}\n\nfunction compactGoals(goals: AdGoalsData) {\n const quiet = goals.accounts.filter(idle);\n return {\n window: goals.window,\n ...(quiet.length > 0\n ? {\n notSpending: quiet.map((account) => ({\n platform: account.platform,\n adAccountId: account.adAccountId,\n name: account.name,\n ...(account.total.target ? { target: compactNumbers(account.total).target } : {}),\n })),\n }\n : {}),\n accounts: goals.accounts\n .filter((account) => !idle(account))\n .map((account) => ({\n platform: account.platform,\n adAccountId: account.adAccountId,\n name: account.name,\n currency: account.currency,\n countsAsResult: account.results.actions.length > 0 ? account.results.actions : \"platform conversions\",\n ...(account.results.source === \"account\" ? {} : { resultChoice: account.results.source }),\n total: compactNumbers(account.total),\n // Split Search targets judge the account, as the dashboard does: read these, not `total.status`.\n ...(account.searchSplit.length > 0\n ? {\n judgedBy: account.searchSplit.map((entry) => ({\n search: entry.segment,\n target: round(entry.value),\n actual: round(entry.actual),\n status: entry.status,\n })),\n }\n : {}),\n ...(account.split ? {} : { note: account.note }),\n events: account.events.map((event) => ({\n event: event.event,\n label: event.label,\n counted: event.counted,\n ...(event.optimisedBy ? { optimisedBy: event.optimisedBy } : {}),\n ...(event.spend === null ? { results: round(event.results), judgedOn: \"account\" } : compactNumbers(event)),\n })),\n ...(account.mismatch ? { mismatch: account.mismatch } : {}),\n ...(account.available.length > 0\n ? { available: account.available.slice(0, 10).map((entry) => entry.event) }\n : {}),\n })),\n };\n}\n\nexport function compactTargets(data: AdPerformanceTargetsData): Record<string, unknown> {\n return {\n headline: targetsHeadline(data.goals),\n companyDefault: data.targets.target ? { metric: data.targets.focus, ...data.targets.target } : null,\n ...(data.targets.platformTargets.length > 0 ? { platformTargets: data.targets.platformTargets } : {}),\n // Google Search keyword classes (brand, competitor, non-brand): win over every other target for those campaigns.\n ...((data.targets.segmentTargets ?? []).length > 0 ? { segmentTargets: data.targets.segmentTargets } : {}),\n ...(data.targets.resultName ? { resultName: data.targets.resultName } : {}),\n goals: compactGoals(data.goals),\n ...(data.staged.length > 0 ? { staged: data.staged } : {}),\n alerts: { ...data.targets.alerts, defaults: data.targets.alertDefaults },\n currencies: data.currencies,\n optimisation: data.focus.platforms.map((platform) => ({\n platform: platform.platform,\n groups: platform.groups.map((group) => ({\n optimisesFor: group.label,\n conversion: group.conversion,\n entities: group.entities,\n spend: roundDeep(group.spend),\n ...(group.countedByGoal === null ? {} : { countedByResult: group.countedByGoal }),\n })),\n result: platform.goalActions.length > 0 ? platform.goalActions : \"platform conversions\",\n ...(platform.suggestion ? { suggestedResult: platform.suggestion.actions } : {}),\n ...(platform.mismatch ? { mismatch: platform.mismatch.message } : {}),\n })),\n ...(accountMismatches(data).length > 0 ? { accountMismatches: accountMismatches(data) } : {}),\n };\n}\n\n/** Accounts whose ads optimise for something the account's result (its own choice, else the platform's) does not count. */\nfunction accountMismatches(data: AdPerformanceTargetsData) {\n return (data.focus.accounts ?? []).flatMap((account) =>\n account.mismatch\n ? [{ platform: account.platform, adAccountId: account.adAccountId, mismatch: account.mismatch.message }]\n : [],\n );\n}\n\nexport function targetsHints(data: AdPerformanceTargetsData): string[] {\n const hints = [HOW_TO_CHANGE];\n if (\n !data.targets.target &&\n data.targets.platformTargets.length === 0 &&\n data.targets.goalTargets.length === 0 &&\n (data.targets.segmentTargets ?? []).length === 0\n )\n hints.push(\n \"No target is set, so there are no budget recommendations. Suggest one per event from what each account achieves (goals.accounts[].events) and what the business can afford.\",\n );\n if (data.staged.length > 0)\n hints.push(\"staged lists what this chat changed: it is not in force until the person publishes the chat.\");\n if (data.goals.accounts.some((account) => !account.split))\n hints.push(\n \"Where an account has a note, its platform cannot split spend by event: judge and target the account as a whole.\",\n );\n if (data.focus.platforms.some((platform) => platform.mismatch) || accountMismatches(data).length > 0)\n hints.push(\n \"A mismatch means cost per result there counts something other than what the platform optimises for: say so before judging those numbers.\",\n );\n if (data.focus.platforms.some((platform) => platform.suggestion))\n hints.push(\n \"suggestedResult is a suggestion: stage it with baker ads performance goals set only after the person agrees.\",\n );\n hints.push(\n \"Read as the Goals page does: targets first (what a result may cost, and whether each account is on it), then the monthly budget with baker ads performance budgets (what each may spend, and where it is heading).\",\n );\n return hints;\n}\n\ntype Recommendation = AdPerformanceBudgetRecommendationsData[\"rows\"][number];\n\n/** Each platform's words for a level, as its `baker ads` commands name them. */\nconst LEVEL_COMMAND: Partial<Record<Recommendation[\"platform\"], Record<Recommendation[\"level\"], string>>> = {\n meta: { campaign: \"campaigns\", ad_group: \"adsets\" },\n google: { campaign: \"campaigns\", ad_group: \"ad-groups\" },\n};\n\n/**\n * The command that stages a move, exactly: a pause, or the suggested daily\n * budget. Google keeps a campaign's money on a shared budget object, so its\n * step is the budget's update, read off the campaign first. Null for a hold,\n * a platform without a one-line step, a budget held by a parent, or an amount\n * converted out of the ad account's own currency (the platform reads it as its own).\n */\nexport function stageCommand(row: Recommendation): string | null {\n const level = LEVEL_COMMAND[row.platform]?.[row.level];\n if (!level || row.waitUntil) return null;\n const where = row.platform === \"google\" ? `--customer-id ${row.adAccountId}` : `--account-id ${row.adAccountId}`;\n if (row.move === \"pause\") return `baker ads ${row.platform} ${level} pause ${row.entityId} ${where}`;\n if ((row.move !== \"scale\" && row.move !== \"cut\") || row.budget.suggestedDaily === null) return null;\n if (row.accountCurrency !== row.currency) return null;\n const amount = Math.round(row.budget.suggestedDaily * 100) / 100;\n if (row.platform === \"google\")\n return row.level === \"campaign\"\n ? `baker ads google budgets update <its budget id, from baker ads google campaigns> ${where} --amount ${amount}`\n : null;\n return `baker ads meta ${level} update ${row.entityId} ${where} --daily-budget ${amount}`;\n}\n\nexport function compactRecommendations(data: AdPerformanceBudgetRecommendationsData): Record<string, unknown> {\n if (!data.hasTarget) return { hasTarget: false };\n return {\n focus: data.focus,\n counts: data.counts,\n rows: data.rows.map((row) => ({\n move: row.move,\n platform: row.platform,\n level: row.level,\n entityId: row.entityId,\n name: row.name,\n ...(row.level === \"ad_group\" ? { campaignName: row.campaignName } : {}),\n currency: row.currency,\n reason: row.reason,\n confidence: row.confidence,\n ...(row.metric === data.focus ? {} : { judgedOn: row.metric }),\n last7: roundDeep({ spend: row.last7.spend, results: row.last7.results, metric: row.last7.metric }),\n last3: roundDeep({ spend: row.last3.spend, results: row.last3.results, metric: row.last3.metric }),\n target: row.target,\n targetFrom: row.targetSegment ?? row.targetSource,\n ...(row.budget.suggestedDaily === null ? {} : { budget: roundDeep(row.budget) }),\n ...(row.alert ? { alertId: row.alert.id } : {}),\n ...(row.alert?.claimedByChatId ? { claimedBy: \"a chat\" } : {}),\n ...(row.alert?.fixing ? { fixed: \"checking it worked\" } : {}),\n ...(stageCommand(row) ? { stage: stageCommand(row) } : {}),\n })),\n ...(data.untargeted.length > 0 ? { untargeted: data.untargeted } : {}),\n };\n}\n\nexport function recommendationsHints(data: AdPerformanceBudgetRecommendationsData): string[] {\n if (!data.hasTarget)\n return [\n \"No target is set. Ask the person what one result is worth to them, then stage it with baker ads performance targets set (or they set it in Measure → Ads → Goals).\",\n ];\n const hints = [\n \"Windows are each platform's last 7 and 3 settled days. A recommendation is advice: apply a budget change only when the person agrees, by staging it with baker ads <platform>, one step at a time (budget.changePct), then wait budget.waitDays.\",\n ];\n if (data.counts.scale + data.counts.cut + data.counts.pause > 0)\n hints.push(\"Before acting on one, read it: baker ads performance entity <id> --platform <p> --level <level>.\");\n if (data.rows.some((row) => row.alert))\n hints.push(\n 'alertId: the move is also an open alert in What needs attention. Claim it (baker ads performance attention claim <alertId>), stage the `stage` command once the person agrees, then baker ads performance attention fixed <alertId> --note \"<what you changed>\". If they decline it, attention dismiss <alertId> --reason \"<why>\".',\n );\n if (data.untargeted.length > 0)\n hints.push(\n `Not judged: campaigns in ${data.untargeted.map((entry) => entry.currency).join(\", \")} have no target that applies (none set for their account, platform or company, or no exchange rate to compare).`,\n );\n return hints;\n}\n\n// --- commands ---\n\nexport const TARGETS_ARGS = {\n days: SCOPE_ARGS.days,\n start: SCOPE_ARGS.start,\n end: SCOPE_ARGS.end,\n platforms: SCOPE_ARGS.platforms,\n currency: SCOPE_ARGS.currency,\n full: SCOPE_ARGS.full,\n} as const;\n\nexport const BUDGET_RECOMMENDATIONS_ARGS = {\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n currency: SCOPE_ARGS.currency,\n moves: { type: \"string\", description: \"Comma list of scale,hold,cut,pause (default all)\", required: false },\n limit: { type: \"string\", description: \"Rows to return, 1-200 (default 50)\", required: false },\n full: SCOPE_ARGS.full,\n} as const;\n\nexport function targetsInput(args: Args) {\n const chatId = optionalOwnChatId();\n return {\n platforms: commaList(args.platforms)?.map((item) => enumValue(item) ?? item),\n days: optionalNumber(args.days),\n start: typeof args.start === \"string\" && args.start !== \"\" ? args.start : undefined,\n end: typeof args.end === \"string\" && args.end !== \"\" ? args.end : undefined,\n currency: typeof args.currency === \"string\" && args.currency !== \"\" ? args.currency : undefined,\n ...(chatId ? { chatId } : {}),\n };\n}\n\nexport function budgetRecommendationsInput(args: Args) {\n return {\n platforms: commaList(args.platforms)?.map((item) => enumValue(item) ?? item),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n currency: typeof args.currency === \"string\" && args.currency !== \"\" ? args.currency : undefined,\n moves: commaList(args.moves)?.map((item) => item.toLowerCase()),\n limit: optionalNumber(args.limit),\n };\n}\n\nexport interface TargetCommandSpec<S extends z.ZodType, D> {\n name: string;\n schemaDescription: string;\n help: string;\n args: ArgsDef;\n request: S;\n input: (args: Args) => unknown;\n compact: (data: D) => unknown;\n hints: (data: D) => string[];\n}\n\nexport function targetCommand<S extends z.ZodType, D>(spec: TargetCommandSpec<S, D>) {\n registerSchema({\n command: `ads.performance.${spec.name}`,\n description: spec.schemaDescription,\n args: spec.args as Parameters<typeof registerSchema>[0][\"args\"],\n });\n return defineCommand({\n meta: { name: spec.name, description: spec.help },\n args: spec.args,\n run: async ({ args }) => {\n const empty = emptyFlagIssues(args, spec.args);\n if (empty.length > 0) failInvalid(empty, spec.args);\n const parsed = spec.request.safeParse(spec.input(args));\n if (!parsed.success) failInvalid(parsed.error.issues, spec.args);\n try {\n const response = await postRead<D>(spec.name, parsed.data);\n const hints = spec.hints(response.data);\n const data = args.full === true ? response.data : spec.compact(response.data);\n writeJson({ ok: true, data, ...(hints.length > 0 ? { hints } : {}) });\n } catch (err) {\n failRead(err);\n }\n },\n });\n}\n\nexport const targetsCommand = targetCommand<typeof adPerformanceTargetsRequestSchema, AdPerformanceTargetsData>({\n name: \"targets\",\n schemaDescription:\n \"Start here for targets and what counts as a result. Per ad account (goals.accounts): what counts as a result there, the period's spend, results and cost per result (or return) against the account's target with a status (on_target, above_target, below_target, not_enough_data, no_target), and one row per event its ads optimise for or count — Meta and LinkedIn cost each event by the spend of the ad groups optimising for it over that event's own count; Google, X and ChatGPT Ads cannot split spend by event (note), so only the account is judged. Targets resolve event at its account → account → platform (older) → company default, each with its own metric (cost_per_result or roas); money targets are converted to compare. Also the alert lines (alerts, with Baker's defaults; change them with targets alert-lines), the currencies a target can be in, what live ad groups optimise for per platform with a suggested result or mismatch, and what this chat staged. Default the last 30 days. Change targets with targets set and results with goals set — staged until the chat is published.\",\n help: \"Targets per ad account and event, against the period's numbers. Example: baker ads performance targets --days 30\",\n args: TARGETS_ARGS,\n request: adPerformanceTargetsRequestSchema,\n input: targetsInput,\n compact: compactTargets,\n hints: targetsHints,\n});\n\nexport const budgetRecommendationsCommand = targetCommand<\n typeof adPerformanceBudgetRecommendationsRequestSchema,\n AdPerformanceBudgetRecommendationsData\n>({\n name: \"budget-recommendations\",\n schemaDescription:\n \"Per active campaign or ad group, scale | hold | cut | pause against the company's target, worst first: cost per result (or ROAS) over each platform's last 7 and 3 settled days against the target and the ad account's spend-weighted average, a one-line reason, a confidence, and a budget step of at most ±20% with the days to wait before the next. Scale only where budget holds it back (Google impression share lost to budget, or ≥90% of the daily budget spent). hasTarget false when no target is set. Read-only: nothing is changed.\",\n help: \"Scale, hold or cut each campaign against the target. Example: baker ads performance budget-recommendations --moves scale,cut\",\n args: BUDGET_RECOMMENDATIONS_ARGS,\n request: adPerformanceBudgetRecommendationsRequestSchema,\n input: budgetRecommendationsInput,\n compact: compactRecommendations,\n hints: recommendationsHints,\n});\n","/**\n * `baker ads performance attention` — the few things that matter most in the\n * ads right now, ranked fix now → worth a look → opportunity, then by money\n * at stake: the same feed the marketer sees at the top of Measure → Ads\n * (`convex/adPerformance/attentionReport.ts`). Read-only.\n */\n\nimport {\n type AdPerformanceAttentionData,\n adAlertClaimRequestSchema,\n adAlertVerdictRequestSchema,\n adPerformanceAttentionRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { optionalChatId } from \"../../../env.ts\";\nimport { commaList, enumValue, optionalNumber, SCOPE_ARGS } from \"./args.ts\";\nimport { withWrites, writeCommand } from \"./goalWrites.ts\";\nimport { targetCommand } from \"./targets.ts\";\n\ntype Args = Record<string, unknown>;\n\n/** Why, whether the reason is new, how often it recurred, what else is wrong with the same thing: only what applies. */\nfunction historyOf(item: AdPerformanceAttentionData[\"items\"][number]): Record<string, unknown> {\n return {\n ...(item.cause ? { why: item.cause } : {}),\n ...(item.previousCause ? { newReason: { was: item.previousCause } } : {}),\n ...(item.timesOpened > 1 ? { timesOpened: item.timesOpened } : {}),\n ...(item.more > 0 ? { moreOnThis: item.more } : {}),\n ...(item.back && item.back !== \"new_reason\" ? { back: item.back } : {}),\n ...(item.handled\n ? {\n fixed: {\n checkingUntil: new Date(item.handled.checkUntil).toISOString().slice(0, 10),\n ...(item.handled.note ? { note: item.handled.note } : {}),\n },\n }\n : {}),\n };\n}\n\n/** Whose an item is: this chat's, another chat's (leave it), or nobody's. */\nfunction claimOf(claimedBy: string | null, chatId: string | undefined): Record<string, string> {\n if (claimedBy === null) return {};\n return { claimedBy: claimedBy === chatId ? \"this chat\" : \"another chat\" };\n}\n\nexport function compactAttention(\n data: AdPerformanceAttentionData,\n chatId?: string,\n): {\n currency: string;\n counts: AdPerformanceAttentionData[\"counts\"];\n items: Array<Record<string, unknown>>;\n dismissedItems?: Array<Record<string, unknown>>;\n} {\n return {\n currency: data.currency,\n counts: data.counts,\n ...(data.dismissedItems.length > 0\n ? {\n dismissedItems: data.dismissedItems.map((item) => ({\n id: item.alertId,\n title: item.title,\n account: item.accountName,\n dismissed: item.dismissal?.kind ?? \"not_now\",\n ...(item.dismissal?.reason ? { reason: item.dismissal.reason } : {}),\n })),\n }\n : {}),\n items: data.items.map((item) => ({\n id: item.alertId,\n tier: item.tier,\n rule: item.rule,\n platform: item.platform,\n account: item.accountName,\n title: item.title,\n ...historyOf(item),\n ...claimOf(item.claimedByChatId, chatId),\n ...(item.target\n ? {\n target: {\n value: Math.round(item.target.value * 100) / 100,\n metric: item.target.metric,\n ...(item.target.currency && item.target.currency !== item.currency\n ? { currency: item.target.currency }\n : {}),\n from: item.target.segment ?? item.target.source,\n },\n }\n : {}),\n ...(item.moneyAtStake === null ? {} : { moneyAtStake: Math.round(item.moneyAtStake) }),\n ...(item.currency !== data.currency ? { currency: item.currency } : {}),\n ...(item.action.open === \"entity\"\n ? { entity: { level: item.action.level, id: item.action.entityId } }\n : { see: item.action.section }),\n })),\n };\n}\n\nexport function attentionHints(data: AdPerformanceAttentionData): string[] {\n const hints: string[] = [];\n if (data.items.some((item) => item.action.open === \"entity\"))\n hints.push(\n \"Before acting on an item, read it: baker ads performance entity <entity.id> --platform <platform> --level <entity.level>. Any change is staged with baker ads <platform> and applies at Publish.\",\n );\n if (data.counts.fix_now > 0)\n hints.push(\"Lead with fix_now items when you tell the person: money is being lost there.\");\n if (data.items.some((item) => item.claimedByChatId !== null))\n hints.push(\n \"claimedBy another chat: someone is already working on it; leave it. To work on an item yourself: baker ads performance attention claim <id>, then release it if you decide not to act.\",\n );\n if (data.items.some((item) => item.previousCause !== null || item.timesOpened > 1))\n hints.push(\n \"newReason: the same problem is back for a different reason than before, so what fixed or excused it then may not apply. timesOpened > 1: it went away and came back; say so.\",\n );\n if (data.items.some((item) => item.handled !== null))\n hints.push(\n \"fixed: someone already fixed it and Baker is checking the fix worked until checkingUntil — do not act on it again. It closes on its own, or comes back as back: fix_did_not_hold.\",\n );\n if (data.items.some((item) => item.back === \"fix_did_not_hold\"))\n hints.push(\n \"back: fix_did_not_hold — it was marked fixed and the problem is still there once the fix had time to show. Read what was changed (baker ads performance changes) before trying the same fix again.\",\n );\n if (!data.hasTarget)\n hints.push(\n \"No target is set, so nothing is judged against one. Ask the person what a result is worth to them, then stage a target per account or event with baker ads performance targets set.\",\n );\n if (data.dismissed > 0 && data.dismissedItems.length === 0)\n hints.push(\n `${data.dismissed} more were dismissed by a person (not_now, or wrong with a reason): add --dismissed to read why before raising one of them again (bring one back with baker ads performance attention restore <id>).`,\n );\n if (data.dismissedItems.length > 0)\n hints.push(\n \"dismissedItems: a person hid these. If one is worth looking at again and the person agrees, stage it back with baker ads performance attention restore <id>.\",\n );\n if (data.items.length === 0) hints.push(\"Nothing needs attention right now: say so in one line.\");\n return hints;\n}\n\nexport const ATTENTION_ARGS = {\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n currency: SCOPE_ARGS.currency,\n tiers: {\n type: \"string\",\n description: \"Comma list of fix_now,worth_a_look,opportunity (default all)\",\n required: false,\n },\n limit: { type: \"string\", description: \"Items to return, 1-100 (default 20)\", required: false },\n dismissed: {\n type: \"boolean\",\n description:\n \"Also list what people dismissed (not_now or wrong) and their reason: read it before raising one again\",\n required: false,\n },\n full: SCOPE_ARGS.full,\n} as const;\n\nexport function attentionInput(args: Args) {\n return {\n platforms: commaList(args.platforms)?.map((item) => enumValue(item) ?? item),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n currency: typeof args.currency === \"string\" && args.currency !== \"\" ? args.currency : undefined,\n tiers: commaList(args.tiers)?.map((item) => enumValue(item) ?? item),\n limit: optionalNumber(args.limit),\n ...(args.dismissed === true ? { includeDismissed: true } : {}),\n };\n}\n\nconst attentionReadCommand = targetCommand<typeof adPerformanceAttentionRequestSchema, AdPerformanceAttentionData>({\n name: \"attention\",\n schemaDescription:\n \"What needs attention in the ads now, ranked: fix_now (money wasted, delivery or tracking broke), worth_a_look (off target, getting worse, ads not earning their spend), opportunity (a campaign beating its target that its budget holds back); then by money at stake in the reporting currency. Each item: its id, tier, rule, platform, ad account, one plain sentence, why (the cause, when Baker can tell), newReason when it came back for a different reason than before, timesOpened when it recurred, moreOnThis when the same campaign has other problems behind it, money at stake, and the campaign/ad to read next (entity) or the section to see. Every item is a stored alert, judged again after each sync and within seconds of a target change: the rule alerts, budget moves against each ad account's target, accounts off target or worse than their 4 weeks before, ads not earning their spend, and accounts that stopped. One item per campaign, ad set, ad or account. Read-only.\",\n help: \"The few things that matter most right now. Example: baker ads performance attention --tiers fix_now\",\n args: ATTENTION_ARGS,\n request: adPerformanceAttentionRequestSchema,\n input: attentionInput,\n compact: (data) => compactAttention(data, optionalChatId()),\n hints: attentionHints,\n});\n\nexport function alertClaimInput(args: Args, chatId: string): Record<string, unknown> {\n return { chatId, alertId: typeof args.id === \"string\" ? args.id.trim() : \"\" };\n}\n\nconst CLAIM_ARGS = {\n id: { type: \"positional\", description: \"The item's id, from baker ads performance attention\", required: true },\n} as const;\n\nconst attentionClaimCommand = writeCommand({\n name: \"claim\",\n schemaName: \"attention.claim\",\n schemaDescription:\n \"Say this chat is working on an alert: the dashboard shows an agent is on it, and no other chat takes it. Applies at once (it is coordination, not a change); it lapses when this chat ends. Refused while another chat works on it. Claim before you start on an item, not to read it.\",\n help: \"Work on an alert.\\n\\nExample:\\n baker ads performance attention claim k57abc\",\n path: \"/api/ads/performance/alerts/claim\",\n args: CLAIM_ARGS,\n request: adAlertClaimRequestSchema,\n input: alertClaimInput,\n});\n\nconst attentionReleaseCommand = writeCommand({\n name: \"release\",\n schemaName: \"attention.release\",\n schemaDescription:\n \"Stop working on an alert this chat claimed, so another chat or a person can take it: when you decide not to act, or hand it back. Refused (CONFLICT) while another chat holds it; state not_claimed when no chat was working on it.\",\n help: \"Let go of an alert.\\n\\nExample:\\n baker ads performance attention release k57abc\",\n path: \"/api/ads/performance/alerts/release\",\n args: CLAIM_ARGS,\n request: adAlertClaimRequestSchema,\n input: alertClaimInput,\n});\n\nexport function alertFixedInput(args: Args, chatId: string): Record<string, unknown> {\n return {\n chatId,\n alertId: typeof args.id === \"string\" ? args.id.trim() : \"\",\n verdict: \"fixed\",\n ...(typeof args.note === \"string\" && args.note.trim() !== \"\" ? { note: args.note } : {}),\n };\n}\n\nexport function alertDismissInput(args: Args, chatId: string): Record<string, unknown> {\n return {\n chatId,\n alertId: typeof args.id === \"string\" ? args.id.trim() : \"\",\n verdict: args.wrong === true ? \"wrong\" : \"not_now\",\n ...(typeof args.reason === \"string\" && args.reason.trim() !== \"\" ? { note: args.reason } : {}),\n };\n}\n\nexport function alertRestoreInput(args: Args, chatId: string): Record<string, unknown> {\n return { chatId, alertId: typeof args.id === \"string\" ? args.id.trim() : \"\", verdict: \"restore\" };\n}\n\nconst attentionFixedCommand = writeCommand({\n name: \"fixed\",\n schemaName: \"attention.fixed\",\n schemaDescription:\n 'Mark an alert fixed once you staged the fix (a budget, bid or status change with baker ads <platform>), with a note of what you changed. Staged on this chat and applied at Publish, with the fix itself. Afterwards the alert shows \"Fixed, checking it worked\" until the fix had time to show in the results, then closes as fixed or comes back as fix_did_not_hold.',\n help: 'Mark an alert fixed.\\n\\nExample:\\n baker ads performance attention fixed k57abc --note \"Cut the daily budget from €80 to €64\"',\n path: \"/api/ads/performance/alerts/verdict\",\n args: {\n ...CLAIM_ARGS,\n note: { type: \"string\", description: \"What you changed, in one line the person reads\", required: false },\n },\n request: adAlertVerdictRequestSchema,\n input: alertFixedInput,\n});\n\nconst attentionDismissCommand = writeCommand({\n name: \"dismiss\",\n schemaName: \"attention.dismiss\",\n schemaDescription:\n 'Dismiss an alert that needs no fix, staged on this chat and applied at Publish. Default \"not now\": true but not worth acting on yet; it comes back when it gets worse, the item is edited, its target moves, or for a new reason. --wrong: it is not a real problem (the person says it is false, or it is on purpose); needs --reason, stays hidden unless it turns critical, and the reason is what the rules are tuned from.',\n help: 'Dismiss an alert.\\n\\nExamples:\\n baker ads performance attention dismiss k57abc --reason \"Waiting for the new creatives\"\\n baker ads performance attention dismiss k57abc --wrong --reason \"Paused on purpose for the holidays\"',\n path: \"/api/ads/performance/alerts/verdict\",\n args: {\n ...CLAIM_ARGS,\n wrong: { type: \"boolean\", description: \"It is not a real problem (needs --reason)\", required: false },\n reason: { type: \"string\", description: \"Why: optional for not now, required with --wrong\", required: false },\n },\n request: adAlertVerdictRequestSchema,\n input: alertDismissInput,\n});\n\nconst attentionRestoreCommand = writeCommand({\n name: \"restore\",\n schemaName: \"attention.restore\",\n schemaDescription:\n \"Bring back an alert a person dismissed (an id from baker ads performance attention --dismissed → dismissedItems), staged on this chat and applied at Publish: it is open on the list again and judged afresh; the dismissal's reason stays kept for tuning the rules. Refused when the alert is not dismissed. Only when the person agrees it is worth looking at again — read why it was dismissed first.\",\n help: \"Bring back a dismissed alert.\\n\\nExample:\\n baker ads performance attention restore k57abc\",\n path: \"/api/ads/performance/alerts/verdict\",\n args: CLAIM_ARGS,\n request: adAlertVerdictRequestSchema,\n input: alertRestoreInput,\n});\n\nexport const attentionCommand = withWrites(attentionReadCommand, {\n claim: attentionClaimCommand,\n release: attentionReleaseCommand,\n fixed: attentionFixedCommand,\n dismiss: attentionDismissCommand,\n restore: attentionRestoreCommand,\n});\n","/**\n * `baker ads performance creative-assets` — every picture and video the ads\n * run, as Baker copied it at the largest size the platform hands over: the\n * originals to make variants from. Read from Baker's own records; nothing here\n * calls an ad platform.\n */\n\nimport {\n type AdCreativeAsset,\n type AdCreativeAssetsData,\n adCreativeAssetsRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { defineCommand } from \"citty\";\nimport { writeJson } from \"../../../output.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { commaList, emptyFlagIssues, enumValue, optionalNumber, SCOPE_ARGS } from \"./args.ts\";\nimport { failInvalid, failRead, postRead } from \"./reportCommand.ts\";\n\ntype Args = Record<string, unknown>;\n\nexport const CREATIVE_ASSETS_ARGS = {\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n \"ad-ids\": { type: \"string\", description: \"Comma list: only what these ads show\", required: false },\n \"ad-group-ids\": {\n type: \"string\",\n description:\n \"Comma list: only what these ad groups / ad sets show — their ads' assets (the first 100 ads by spend) and a Performance Max asset group's own\",\n required: false,\n },\n kinds: { type: \"string\", description: \"Comma list of image,video (default both)\", required: false },\n statuses: {\n type: \"string\",\n description: \"Comma list of stored,pending,unavailable,too-large,failed (default all)\",\n required: false,\n },\n limit: { type: \"string\", description: \"Assets returned, 1-500 (default 100)\", required: false },\n full: {\n type: \"boolean\",\n description: \"Every field: the platform's own link, every use with its role and placement, timestamps\",\n required: false,\n default: false,\n },\n} as const;\n\nexport function creativeAssetsInput(args: Args) {\n return {\n platforms: commaList(args.platforms)?.map((item) => enumValue(item) ?? item),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n adIds: commaList(args[\"ad-ids\"]),\n adGroupIds: commaList(args[\"ad-group-ids\"]),\n kinds: commaList(args.kinds)?.map((item) => enumValue(item) ?? item),\n statuses: commaList(args.statuses)?.map((item) => enumValue(item) ?? item),\n limit: optionalNumber(args.limit),\n };\n}\n\n/** One asset as the agent needs it to pick an original: the file, its size, and what it is in which ad. */\nfunction compactAsset(asset: AdCreativeAsset): Record<string, unknown> {\n const roles = [...new Set(asset.uses.map((use) => (use.placement ? `${use.role} (${use.placement})` : use.role)))];\n return Object.fromEntries(\n Object.entries({\n platform: asset.platform,\n kind: asset.kind,\n id: asset.platformAssetId,\n status: asset.status,\n url: asset.url,\n posterUrl: asset.posterUrl,\n youtubeUrl: asset.youtubeUrl,\n size: asset.width && asset.height ? `${asset.width}x${asset.height}` : null,\n aspectRatio: asset.aspectRatio,\n seconds: asset.durationSeconds === null ? null : Math.round(asset.durationSeconds * 10) / 10,\n mb: asset.bytes === null ? null : Math.round(asset.bytes / 10_000) / 100,\n name: asset.name,\n roles: roles.length > 0 ? roles : null,\n ads: asset.useCount,\n note: asset.note,\n }).filter(([, value]) => value !== null),\n );\n}\n\nexport function compactCreativeAssets(data: AdCreativeAssetsData): Record<string, unknown> {\n return { counts: data.counts, assets: data.assets.map(compactAsset), ...(data.more ? { more: true } : {}) };\n}\n\n/** The request's narrowing filters: with any of them set, an empty list says nothing about what is stored. */\nconst ASSET_FILTERS = [\"platforms\", \"adAccountIds\", \"adIds\", \"adGroupIds\", \"kinds\", \"statuses\"] as const;\n\nexport function creativeAssetsHints(\n data: AdCreativeAssetsData,\n request: Partial<Record<(typeof ASSET_FILTERS)[number], readonly string[]>> = {},\n): string[] {\n const hints: string[] = [];\n if (data.assets.length === 0) {\n const filtered = ASSET_FILTERS.some((filter) => (request[filter]?.length ?? 0) > 0);\n hints.push(\n filtered\n ? \"Nothing matches these filters. Check the ids (baker ads performance entities --level ad), or widen --platforms, --kinds or --statuses.\"\n : \"No creative files are stored yet. They are copied after each ad sync (every few hours); check baker ads performance status.\",\n );\n return hints;\n }\n hints.push(\n \"url is Baker's permanent copy of the original: download it to make a variant (keep the aspect ratio of the placement it was for).\",\n );\n if (data.counts.pending > 0) hints.push(`${data.counts.pending} copies are still on their way; ask again later.`);\n if (data.assets.some((asset) => asset.youtubeUrl !== null))\n hints.push(\n \"Google Ads videos live on YouTube and cannot be downloaded: use youtubeUrl and the cover in posterUrl.\",\n );\n if (data.assets.some((asset) => asset.platform === \"linkedin\"))\n hints.push(\"LinkedIn assets are the ad account's media library: LinkedIn does not say which ad shows which.\");\n if (data.more && (request.adGroupIds?.length ?? 0) > 0)\n hints.push(\n \"More may match: an ad group's assets are read from its first 100 ads by spend. For the rest, list its ads with baker ads performance entities --level ad --ad-group-ids <id> and pass them as --ad-ids.\",\n );\n else if (data.more) hints.push(\"More assets match: narrow with --ad-ids, --kinds or --platforms, or raise --limit.\");\n return hints;\n}\n\n// --- command ---\n\nregisterSchema({\n command: \"ads.performance.creativeAssets\",\n description:\n \"Every picture and video the ads run, copied by Baker at the largest size each platform hands over — the originals to create variants from. One row per file (deduped across ads): kind, status (stored | pending | unavailable | too_large | failed), url (Baker's permanent copy), posterUrl (a video's cover), size and aspectRatio, seconds, mb, roles (what it is in the ad: image, video, carousel_card, square_marketing_image, logo… with the placements a placement version is for) and how many ads use it. Meta: every image at its uploaded size, each placement version, carousel card and asset-feed variant; videos at the quality Meta streams (up to 720p), and only from Pages the connection manages. Google: every image asset in every ratio, Performance Max included; videos are YouTube links plus cover. LinkedIn: the ad account's media library, not tied to ads. X: the promoted posts' photos (original size) and videos (highest bitrate). ChatGPT Ads: each ad's image. --full adds the platform links, every use and timestamps.\",\n args: CREATIVE_ASSETS_ARGS as Parameters<typeof registerSchema>[0][\"args\"],\n});\n\nexport const creativeAssetsCommand = defineCommand({\n meta: {\n name: \"creative-assets\",\n description:\n \"Start here to make a variant of an existing ad: every version of its pictures and videos, stored at full size. Example: baker ads performance creative-assets --ad-ids <ad id>\",\n },\n args: CREATIVE_ASSETS_ARGS,\n run: async ({ args }) => {\n const empty = emptyFlagIssues(args, CREATIVE_ASSETS_ARGS);\n if (empty.length > 0) failInvalid(empty, CREATIVE_ASSETS_ARGS);\n const parsed = adCreativeAssetsRequestSchema.safeParse(creativeAssetsInput(args));\n if (!parsed.success) failInvalid(parsed.error.issues, CREATIVE_ASSETS_ARGS);\n try {\n const response = await postRead<AdCreativeAssetsData>(\"creative-assets\", parsed.data);\n const hints = creativeAssetsHints(response.data, parsed.data);\n const data = args.full === true ? response.data : compactCreativeAssets(response.data);\n writeJson({ ok: true, data, ...(hints.length > 0 ? { hints } : {}) });\n } catch (err) {\n failRead(err);\n }\n },\n});\n","/**\n * `baker ads performance creative-health` — which creatives the platforms are\n * pushing, which active ads are not earning their spend, how often a new\n * creative becomes a winner, and how much of the money goes to fresh creative\n * (`convex/adPerformance/creativeHealth.ts`). Read-only, from Baker's store.\n * The pure half (flags, request, compact view, hints) is exported for tests.\n */\n\nimport {\n AD_FRESHNESS_NEW_DAYS,\n AD_FRESHNESS_PERIOD_DAYS,\n type AdCreativeHealthData,\n type AdFreshnessCurrency,\n type AdFreshnessNewDays,\n type AdFreshnessPeriodDays,\n type AdHitRateAccount,\n adCreativeHealthRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { defineCommand } from \"citty\";\nimport { writeJson } from \"../../../output.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { commaList, emptyFlagIssues, enumValue, optionalNumber, optionalString, SCOPE_ARGS } from \"./args.ts\";\nimport { roundDeep, roundNumber } from \"./report.ts\";\nimport { failInvalid, failRead, postRead } from \"./reportCommand.ts\";\n\ntype Args = Record<string, unknown>;\n\nexport interface FreshnessChoice {\n newDays: AdFreshnessNewDays;\n periodDays: AdFreshnessPeriodDays;\n}\n\nconst COMPACT_ROWS = 15;\n\nexport const CREATIVE_HEALTH_ARGS = {\n sections: {\n type: \"string\",\n description: \"Comma list of trending,poor,hit-rate,freshness (default all)\",\n required: false,\n },\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n currency: SCOPE_ARGS.currency,\n \"group-by\": {\n type: \"string\",\n description: \"creative (default: the same picture or video counts once across its ads) or ad\",\n required: false,\n },\n months: { type: \"string\", description: \"Launch months for the hit rate, 2-12 (default 6)\", required: false },\n new: {\n type: \"string\",\n description: \"Freshness: a creative counts as new up to 7, 14 (default) or 30 days after launch\",\n required: false,\n },\n over: {\n type: \"string\",\n description: \"Freshness: measure the share over 1 (yesterday), 7 or 14 (default) days\",\n required: false,\n },\n full: {\n type: \"boolean\",\n description: \"Every list, tile and creative, unrounded, instead of the compact view\",\n required: false,\n default: false,\n },\n} as const;\n\nexport function creativeHealthInput(args: Args) {\n return {\n sections: commaList(args.sections)?.map((item) => enumValue(item) ?? item),\n platforms: commaList(args.platforms)?.map((item) => enumValue(item) ?? item),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n groupBy: enumValue(args[\"group-by\"]),\n months: optionalNumber(args.months),\n currency: optionalString(args.currency),\n };\n}\n\ninterface FlagIssue {\n path: [string];\n message: string;\n}\n\n/** The flag's value when it is one of `allowed`, the fallback when it is absent, an issue otherwise. */\nfunction pick<T extends number>(\n allowed: readonly T[],\n args: Args,\n flag: \"new\" | \"over\",\n fallback: T,\n issues: FlagIssue[],\n): T {\n const value = optionalNumber(args[flag]);\n if (value === undefined) return fallback;\n const match = allowed.find((entry) => entry === value);\n if (match !== undefined) return match;\n issues.push({ path: [flag], message: `must be one of ${allowed.join(\", \")} (got ${String(args[flag]).trim()})` });\n return fallback;\n}\n\n/** The freshness tile asked for, and the issues of a --new or --over it cannot measure. */\nfunction freshnessChoice(args: Args): { choice: FreshnessChoice; issues: FlagIssue[] } {\n const issues: FlagIssue[] = [];\n const choice = {\n newDays: pick(AD_FRESHNESS_NEW_DAYS, args, \"new\", 14, issues),\n periodDays: pick(AD_FRESHNESS_PERIOD_DAYS, args, \"over\", 14, issues),\n };\n return { choice, issues };\n}\n\n// --- compact ---\n\nfunction nullableRound(value: number | null): number | null {\n return value === null ? null : roundNumber(value);\n}\n\nfunction compactFreshness(currency: AdFreshnessCurrency, choice: FreshnessChoice) {\n const tile = currency.tiles.find((t) => t.newDays === choice.newDays && t.periodDays === choice.periodDays) ?? null;\n return {\n currency: currency.currency,\n platforms: currency.platforms,\n newDays: choice.newDays,\n tile: tile ? roundDeep(tile) : null,\n weekly: currency.weeks.map((week) => ({\n to: week.to,\n spend: roundNumber(week.spend),\n freshShare: nullableRound(week.freshShares.find((s) => s.newDays === choice.newDays)?.share ?? null),\n costPerResult: nullableRound(week.costPerResult),\n settled: week.settled,\n })),\n comparison: roundDeep(currency.comparisons.find((c) => c.newDays === choice.newDays) ?? null),\n ...(currency.beforeHistoryShare ? { beforeHistoryShare: roundNumber(currency.beforeHistoryShare) } : {}),\n };\n}\n\nfunction compactHitRate(account: AdHitRateAccount) {\n return {\n platform: account.platform,\n adAccountId: account.adAccountId,\n currency: account.currency,\n accountCostPerResult: nullableRound(account.accountCostPerResult),\n winnerSpend: nullableRound(account.winnerSpend),\n months: account.months.map((month) => ({\n month: month.month,\n launches: month.launches,\n winners: month.winners,\n ...(month.maturing ? { maturing: true } : {}),\n top: month.creatives.slice(0, 3).map((creative) => ({\n name: creative.name || creative.headline,\n spend: roundNumber(creative.spend),\n ...(creative.winner ? { winner: true } : {}),\n })),\n })),\n };\n}\n\nexport function compactCreativeHealth(data: AdCreativeHealthData, choice: FreshnessChoice): Record<string, unknown> {\n return {\n groupBy: data.groupBy,\n asOf: data.matureThrough.map((entry) => ({ platform: entry.platform, date: entry.date })),\n ...(data.trending\n ? {\n trending: data.trending.rows.slice(0, COMPACT_ROWS).map((row) => ({\n name: row.name || row.headline,\n platform: row.platform,\n adAccountId: row.adAccountId,\n topAdId: row.topAdId,\n currency: row.currency,\n spend: roundNumber(row.spend),\n previousSpend: roundNumber(row.previousSpend),\n change: row.isNew ? \"new\" : row.restarted ? \"restarted\" : roundNumber(row.spendChange ?? 0),\n costPerResult: nullableRound(row.costPerResult),\n ctr: nullableRound(row.ctr),\n ...(row.videoViewRate === null ? {} : { videoViewRate: roundNumber(row.videoViewRate) }),\n })),\n }\n : {}),\n ...(data.poor\n ? {\n poor: {\n checkedAds: data.poor.checkedAds,\n rows: data.poor.rows.slice(0, COMPACT_ROWS).map((row) => ({\n name: row.name || row.headline,\n platform: row.platform,\n adId: row.adId,\n adGroup: row.adGroupName,\n currency: row.currency,\n reason: row.reason,\n spend: roundNumber(row.spend),\n results: roundNumber(row.results),\n costPerResult: nullableRound(row.costPerResult),\n baseline: row.baseline,\n baselineCostPerResult: roundNumber(row.baselineCostPerResult),\n ...(row.costRatio === null ? {} : { costRatio: roundNumber(row.costRatio) }),\n ageDays: row.ageDays,\n })),\n },\n }\n : {}),\n ...(data.hitRate ? { hitRate: data.hitRate.accounts.map(compactHitRate) } : {}),\n ...(data.freshness ? { freshness: data.freshness.currencies.map((c) => compactFreshness(c, choice)) } : {}),\n };\n}\n\n// --- hints ---\n\nfunction money(amount: number, currency: string): string {\n return `${roundNumber(amount)} ${currency}`;\n}\n\nfunction pct(share: number): string {\n return `${Math.round(share * 100)}%`;\n}\n\nfunction freshnessHints(currencies: readonly AdFreshnessCurrency[], choice: FreshnessChoice): string[] {\n return currencies.flatMap((currency) => {\n const c = currency.comparisons.find((entry) => entry.newDays === choice.newDays);\n const hints: string[] = [];\n if (c) {\n hints.push(\n `${currency.currency}: in the ${c.weeks} settled weeks with the most spend on creatives up to ${c.newDays} days old (about ${pct(c.freshWeeksShare)}), the median cost per result was ${money(c.freshWeeksMedianCostPerResult, currency.currency)}, against ${money(c.staleWeeksMedianCostPerResult, currency.currency)} in the ${c.weeks} weeks with the least (about ${pct(c.staleWeeksShare)}). Say it is a correlation between weeks, not proof that fresh creative caused it.`,\n );\n }\n if ((currency.beforeHistoryShare ?? 0) > 0.2) {\n hints.push(\n `${currency.currency}: ${pct(currency.beforeHistoryShare ?? 0)} of the spend went to creatives already running when Baker's stored history begins; their age is a lower bound.`,\n );\n }\n return hints;\n });\n}\n\nexport function creativeHealthHints(data: AdCreativeHealthData, choice: FreshnessChoice): string[] {\n const hints: string[] = [];\n if (data.trending && data.trending.rows.length > 0) {\n hints.push(\n \"Trending means the platform is putting more money behind it, not that it works: read its costPerResult before calling it a winner. videoViewRate is each platform's own video view (Meta ThruPlays, Google views, LinkedIn and X video views) over impressions.\",\n );\n }\n if (data.poor && data.poor.rows.length > 0) {\n const first = data.poor.rows[0];\n hints.push(\n `Before pausing a poor performer, read it: \\`baker ads performance entity ${first?.adId ?? \"<ad id>\"} --platform ${first?.platform ?? \"<platform>\"} --level ad\\`. Pausing is a staged change applied at Publish.`,\n );\n }\n if (data.hitRate?.accounts.some((account) => account.months.some((month) => month.maturing))) {\n hints.push(\n `Months marked maturing still have launches inside their first ${data.hitRate.cohortDays} days: their winner count can still rise.`,\n );\n }\n if (data.freshness) hints.push(...freshnessHints(data.freshness.currencies, choice));\n hints.push(\"Money is in the reporting currency (--currency); never add amounts across currencies.\");\n return hints;\n}\n\n// --- command ---\n\nregisterSchema({\n command: \"ads.performance.creativeHealth\",\n description:\n \"Creative health from Baker's stored ad data, every platform with creatives. trending: creatives whose spend grew more than 35% over the last 7 settled days against the 7 before (change: new | restarted | relative growth), with cost per result, CTR and video view rate. poor: active ads at least 14 days old costing far more per result than their ad set (shrunk, costRatio) or with no results after spending 3× the ad set's cost per result. hitRate: per ad account and launch month, creatives launched and winners (spend ≥ 10× the account's cost per result within 90 days; winnerSpend is that bar); maturing months can still gain winners. freshness: share of spend on creatives up to --new days old over --over days against the period before, spend-weighted creative age, fresh vs stale cost per result, 13 weekly shares and a fresh-vs-stale weeks comparison (a correlation, never a cause). --full returns every list.\",\n args: CREATIVE_HEALTH_ARGS as Parameters<typeof registerSchema>[0][\"args\"],\n});\n\nexport const creativeHealthCommand = defineCommand({\n meta: {\n name: \"creative-health\",\n description:\n \"Trending creatives, poor performers, launch hit rate and creative freshness. Example: baker ads performance creative-health --sections trending,poor\",\n },\n args: CREATIVE_HEALTH_ARGS,\n run: async ({ args }) => {\n const empty = emptyFlagIssues(args, CREATIVE_HEALTH_ARGS);\n if (empty.length > 0) failInvalid(empty, CREATIVE_HEALTH_ARGS);\n const parsed = adCreativeHealthRequestSchema.safeParse(creativeHealthInput(args));\n const { choice, issues } = freshnessChoice(args);\n if (!parsed.success || issues.length > 0) {\n failInvalid([...(parsed.success ? [] : parsed.error.issues), ...issues], CREATIVE_HEALTH_ARGS);\n }\n try {\n const response = await postRead<AdCreativeHealthData>(\"creative-health\", parsed.data);\n const hints = creativeHealthHints(response.data, choice);\n const data = args.full === true ? response.data : compactCreativeHealth(response.data, choice);\n writeJson({ ok: true, data, ...(hints.length > 0 ? { hints } : {}) });\n } catch (err) {\n failRead(err);\n }\n },\n});\n","/**\n * `baker ads performance currency | currency set` — the company's reporting\n * currency: what every Ads screen, report and `baker ads performance` read\n * shows amounts in unless asked otherwise, how it was decided, and the\n * currencies it can be (`convex/adPerformance/reportingCurrency.ts`). Setting\n * it is staged on this chat and applies when the person publishes it, as the\n * dashboard's \"Use as default\" in the Show-in picker does at once.\n */\n\nimport {\n type AdReportingCurrencyData,\n type AdReportingCurrencySource,\n adReportingCurrencyRequestSchema,\n adReportingCurrencyStageRequestSchema,\n} from \"@baker/api/ads-performance/currency\";\nimport { optionalOwnChatId } from \"../../../env.ts\";\nimport { optionalString, SCOPE_ARGS } from \"./args.ts\";\nimport { withWrites, writeCommand } from \"./goalWrites.ts\";\nimport { report } from \"./reportCommand.ts\";\n\ntype Args = Record<string, unknown>;\n\nconst SOURCE_WORDS: Record<AdReportingCurrencySource, string> = {\n saved: \"A person saved it as the default.\",\n only_account_currency: \"Nobody saved one, and every ad account is in this currency.\",\n default: \"Nobody saved one and no ad account is connected, so Baker uses EUR.\",\n most_spend: \"Nobody saved one, so Baker uses the currency the company spent most in over the last 30 days.\",\n};\n\nexport function compactCurrency(data: AdReportingCurrencyData) {\n return {\n currency: data.currency,\n why: SOURCE_WORDS[data.source],\n saved: data.saved,\n accountCurrencies: data.accountCurrencies,\n canShowIn: data.convertible,\n ...(data.staged ? { staged: { before: data.staged.before, after: data.staged.after } } : {}),\n };\n}\n\nexport function currencyHints(data: AdReportingCurrencyData): string[] {\n const hints = [\n \"Any read can show another currency for one answer with --currency <ISO> (or native for each account's own): that changes nothing for anyone else.\",\n \"To change what everyone sees by default, once the person asks: baker ads performance currency set <ISO>, or --clear to go back to the currency spent most in. It applies when the chat is published.\",\n ];\n if (data.staged)\n hints.push(\n `staged: this chat changes the reporting currency to ${data.staged.after}, not in force until the person publishes the chat. Take it back with baker ads performance targets unstage ${data.staged.key}.`,\n );\n return hints;\n}\n\nexport function currencySetInput(args: Args, chatId: string): Record<string, unknown> {\n const currency = optionalString(args.currency);\n return {\n chatId,\n ...(args.clear === true ? { currency: null } : currency !== undefined ? { currency } : {}),\n };\n}\n\nconst currencyReadCommand = report<typeof adReportingCurrencyRequestSchema, AdReportingCurrencyData>({\n name: \"currency\",\n schemaName: \"currency\",\n schemaDescription:\n \"The company's reporting currency: what every Ads screen, report and baker ads performance read shows money in unless asked otherwise (--currency). Returns the currency, why it is the one (saved by a person, the accounts' only currency, or the one spent most in over the last 30 days), the saved default (null when none), the ad accounts' currencies, every currency an amount can be shown in (ECB rates), and what this chat staged. Read-only; change it with currency set.\",\n help: \"The company's reporting currency and why. Example: baker ads performance currency\",\n path: \"currency\",\n args: { full: SCOPE_ARGS.full },\n request: adReportingCurrencyRequestSchema,\n input: () => {\n const chatId = optionalOwnChatId();\n return chatId ? { chatId } : {};\n },\n compact: compactCurrency,\n hints: currencyHints,\n});\n\nconst currencySetCommand = writeCommand({\n name: \"set\",\n schemaName: \"currency.set\",\n schemaDescription:\n \"Stage the company's reporting currency, the default every person and the agent see money in: an ISO code it can show (canShowIn from baker ads performance currency), or --clear to go back to the currency spent most in. Applies when the person publishes the chat, like Use as default in the dashboard's Show-in picker; a currency a person saved meanwhile stays. Only when the person asks to change the default for everyone: for one answer, pass --currency to the read instead.\",\n help: \"Stage the reporting currency; it applies when the chat is published.\\n\\nExamples:\\n baker ads performance currency set USD\\n baker ads performance currency set --clear\",\n path: \"/api/ads/performance/currency/set\",\n args: {\n currency: { type: \"positional\", description: \"An ISO currency code, e.g. USD\", required: false },\n clear: {\n type: \"boolean\",\n description: \"Forget the saved currency: Baker uses the one spent most in again\",\n required: false,\n },\n },\n request: adReportingCurrencyStageRequestSchema,\n input: currencySetInput,\n exclusive: [[[\"currency\"], [\"clear\"]]],\n});\n\nexport const currencyCommand = withWrites(currencyReadCommand, { set: currencySetCommand });\n","/**\n * `baker ads performance anomalies | recap` — the day-grain diagnostic: which\n * of each ad account's last settled days were unusual, what carried them,\n * what changed near them and whether the conversion events still record\n * (`convex/adPerformance/anomalies.ts`); and the last days of changes as plain\n * sentences (`changeRecap.ts`). Read-only, from Baker's store.\n */\n\nimport {\n type AdAnomalyAccount,\n type AdPerformanceAnomaliesData,\n type AdPerformanceRecapData,\n adPerformanceAnomaliesRequestSchema,\n adPerformanceRecapRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { type ArgsDef, defineCommand } from \"citty\";\nimport type { z } from \"zod\";\nimport { writeJson } from \"../../../output.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { commaList, emptyFlagIssues, enumValue, optionalNumber, optionalString, SCOPE_ARGS } from \"./args.ts\";\nimport { roundNumber } from \"./report.ts\";\nimport { failInvalid, failRead, postRead } from \"./reportCommand.ts\";\n\n// --- flags ---\n\nconst ANOMALIES_ARGS = {\n days: { type: \"string\", description: \"Settled days to scan, 7-28 (default 14)\", required: false },\n end: {\n type: \"string\",\n description: \"Last day to scan, YYYY-MM-DD (default each platform's last settled day)\",\n required: false,\n },\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n currency: SCOPE_ARGS.currency,\n \"cpa-spike\": {\n type: \"string\",\n description:\n \"How far above its usual a day's cost per result must be to count, e.g. 0.3 = 30% (default 0.5). Pass the company's own threshold when it has one\",\n required: false,\n },\n full: SCOPE_ARGS.full,\n} as const;\n\nconst RECAP_ARGS = {\n days: { type: \"string\", description: \"Days back, today included, 1-31 (default 7)\", required: false },\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n full: SCOPE_ARGS.full,\n} as const;\n\ntype Args = Record<string, unknown>;\n\nconst platformList = (args: Args) => commaList(args.platforms)?.map((item) => enumValue(item) ?? item);\n\nexport function anomaliesInput(args: Args) {\n return {\n days: optionalNumber(args.days),\n end: optionalString(args.end),\n platforms: platformList(args),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n cpaSpike: optionalNumber(args[\"cpa-spike\"]),\n currency: optionalString(args.currency),\n };\n}\n\nexport function recapInput(args: Args) {\n return {\n days: optionalNumber(args.days),\n platforms: platformList(args),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n };\n}\n\n// --- compact ---\n\nconst nullableRound = (value: number | null) => (value === null ? null : roundNumber(value));\n\nfunction compactAccount(account: AdAnomalyAccount): Record<string, unknown> {\n return {\n platform: account.platform,\n adAccountId: account.adAccountId,\n name: account.accountName,\n currency: account.currency,\n status: account.status,\n headline: account.headline,\n window: { from: account.window.from, to: account.window.to },\n spend: roundNumber(account.window.spend),\n costPerResult: nullableRound(account.window.costPerResult),\n usualCostPerResult: nullableRound(account.baseline.costPerResult),\n anomalies: account.anomalies.map((period) => ({\n kind: period.kind,\n from: period.anomaly.from,\n to: period.anomaly.to,\n spend: roundNumber(period.anomaly.spend),\n results: roundNumber(period.anomaly.results),\n expectedResults: roundNumber(period.expectedResults),\n costPerResult: nullableRound(period.anomaly.costPerResult),\n before: {\n from: period.before.from,\n to: period.before.to,\n spend: roundNumber(period.before.spend),\n costPerResult: nullableRound(period.before.costPerResult),\n },\n factors: period.factors.map((factor) => ({\n level: factor.level,\n entityId: factor.entityId,\n name: factor.name,\n ...(factor.adGroupName ? { adGroup: factor.adGroupName } : {}),\n campaign: factor.campaignName,\n spend: roundNumber(factor.spend),\n previousSpend: roundNumber(factor.previousSpend),\n spendChangePct: nullableRound(factor.spendChangePct),\n costPerResult: nullableRound(factor.costPerResult),\n previousCostPerResult: nullableRound(factor.previousCostPerResult),\n })),\n changes: period.changes.map((change) => change.summary),\n })),\n };\n}\n\nexport function compactAnomalies(data: AdPerformanceAnomaliesData) {\n return {\n through: data.through,\n accounts: data.accounts.map(compactAccount),\n events: data.events.map((event) => ({\n platform: event.platform,\n adAccountId: event.adAccountId,\n event: event.label,\n status: event.status,\n lastDay: event.lastDay,\n sentence: event.sentence,\n })),\n };\n}\n\nexport function compactRecap(data: AdPerformanceRecapData) {\n return { window: data.window, lines: data.lines.map((line) => line.sentence) };\n}\n\n// --- hints ---\n\nexport function anomaliesHints(data: AdPerformanceAnomaliesData): string[] {\n const hints: string[] = [];\n const broken = data.events.filter((event) => event.status === \"stale\" || event.status === \"never\");\n if (broken.length > 0) {\n hints.push(\n `Check these conversion events first — while one is not recording, every cost per result built on it is wrong: ${broken.map((event) => `\"${event.label}\" (${event.platform} ${event.adAccountId}, ${event.status})`).join(\"; \")}. Ask the user to submit a test conversion on the site and check the event is still connected on the platform.`,\n );\n }\n if (data.accounts.some((account) => account.status === \"anomaly\")) {\n hints.push(\n \"Report each unusual stretch with its days and numbers, then the contributing factors and the nearby changes as facts. Do not say a change caused it: `baker ads performance impact` judges a named change, `baker ads performance diagnose` one entity over weeks.\",\n );\n }\n if (data.accounts.some((account) => account.status === \"too_few_results\")) {\n hints.push(\n \"too_few_results: the four weeks before hold under 10 results, so no day can be called unusual; judge those accounts weekly with `baker ads performance progress`.\",\n );\n }\n hints.push(\n \"Event health is by whole day (no time of day is stored): 'none since 3 Oct' means no record on any day after it, through yesterday. --full adds the daily series.\",\n );\n return hints;\n}\n\nexport function recapHints(data: AdPerformanceRecapData): string[] {\n const hints = [\n \"These are facts — what changed, when, by whom — never why. Add your own reading only from other reads (e.g. `baker ads performance impact`), and say it is yours.\",\n ];\n if (data.readChanges < data.totalChanges) {\n hints.push(\n `Only the newest ${data.readChanges} of ${data.totalChanges} changes were read; pass a shorter --days or --platforms for the rest.`,\n );\n }\n return hints;\n}\n\n// --- commands ---\n\ninterface DiagnosticSpec<S extends z.ZodType, D> {\n name: string;\n schemaName: string;\n schemaDescription: string;\n help: string;\n path: string;\n args: ArgsDef;\n request: S;\n input: (args: Args) => unknown;\n compact: (data: D) => unknown;\n hints: (data: D) => string[];\n}\n\nfunction diagnosticCommand<S extends z.ZodType, D>(spec: DiagnosticSpec<S, D>) {\n registerSchema({\n command: `ads.performance.${spec.schemaName}`,\n description: spec.schemaDescription,\n args: spec.args as Parameters<typeof registerSchema>[0][\"args\"],\n });\n return defineCommand({\n meta: { name: spec.name, description: spec.help },\n args: spec.args,\n run: async ({ args }) => {\n const empty = emptyFlagIssues(args, spec.args);\n if (empty.length > 0) failInvalid(empty, spec.args);\n const parsed = spec.request.safeParse(spec.input(args));\n if (!parsed.success) failInvalid(parsed.error.issues, spec.args);\n try {\n const response = await postRead<D>(spec.path, parsed.data);\n const hints = spec.hints(response.data);\n const data = args.full === true ? response.data : spec.compact(response.data);\n writeJson({ ok: true, data, ...(hints.length > 0 ? { hints } : {}) });\n } catch (err) {\n failRead(err);\n }\n },\n });\n}\n\nexport const anomaliesCommand = diagnosticCommand<\n typeof adPerformanceAnomaliesRequestSchema,\n AdPerformanceAnomaliesData\n>({\n name: \"anomalies\",\n schemaName: \"anomalies\",\n schemaDescription:\n \"Did something break on particular days? Per ad account, its last 14 settled days (each platform's last settled day: matureThrough) scanned day by day: status anomaly | clear | too_few_results | no_spend, a headline, and each unusual stretch — spend, results and cost per result against the same number of days before, the ad groups and ads that carried over 25% of its spend and moved over 15% (factors), and budget steps over 25% and targeting, goal, status and launch changes near it (changes). A stretch is unusual when cost per result is 50% above the four weeks before (--cpa-spike) and so few results are unlikely at the usual rate — small accounts are not flagged for an ordinary empty day. Days still being counted are never flagged. Plus event health: each conversion event the ads optimise for (and each goal action) with the last day it recorded and whether the silence since is longer than its usual rate allows (recording | stale | quiet | never | rare). Complements progress (weekly, per entity). Read-only, from Baker's store. --full adds the daily series.\",\n help: \"Unusual days in the last two weeks, and whether conversion events still record. Example: baker ads performance anomalies\",\n path: \"anomalies\",\n args: ANOMALIES_ARGS,\n request: adPerformanceAnomaliesRequestSchema,\n input: anomaliesInput,\n compact: compactAnomalies,\n hints: anomaliesHints,\n});\n\nexport const recapCommand = diagnosticCommand<typeof adPerformanceRecapRequestSchema, AdPerformanceRecapData>({\n name: \"recap\",\n schemaName: \"recap\",\n schemaDescription:\n \"The last 7 days of changes (--days) as a media buyer's recap: one plain sentence per day, ad account, who and kind of change — launches, ads or ad sets turned on or paused, budgets raised or lowered by how much, targeting, goal, creative and name edits — saying who made them (a person in the platform, Baker with its chat, or the platform automatically) and when. Facts only, never a reason. Newest first. --full adds counts, kinds and entity ids per line. Read-only, from Baker's store.\",\n help: \"This week's changes in plain sentences. Example: baker ads performance recap --days 7\",\n path: \"recap\",\n args: RECAP_ARGS,\n request: adPerformanceRecapRequestSchema,\n input: recapInput,\n compact: compactRecap,\n hints: recapHints,\n});\n","/**\n * `baker ads performance health` — an ad account's health at a glance: spend\n * against last month, cost per result against the week before, traffic costs,\n * the share of budget still learning, new people against people who know the\n * brand, copy slots used by the top ads, weekly frequency, the monthly line and\n * customer segments (`convex/adPerformance/accountHealth.ts`). Read-only, from\n * Baker's store. The pure half (request, compact view, hints) is exported for tests.\n */\n\nimport {\n AD_COPY_VARIANTS_MAX,\n AD_LEARNING_SHARE_THRESHOLDS,\n type AdPerformanceHealthData,\n adPerformanceHealthRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { defineCommand } from \"citty\";\nimport { writeJson } from \"../../../output.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { commaList, emptyFlagIssues, enumValue, SCOPE_ARGS } from \"./args.ts\";\nimport { roundDeep } from \"./report.ts\";\nimport { failInvalid, failRead, postRead } from \"./reportCommand.ts\";\n\ntype Args = Record<string, unknown>;\n\nexport const HEALTH_ARGS = {\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n currency: SCOPE_ARGS.currency,\n full: {\n type: \"boolean\",\n description: \"Every table: learning ad sets, audience table, top ads' copy, weekly reach and segments\",\n required: false,\n default: false,\n },\n} as const;\n\nexport function healthInput(args: Args) {\n return {\n platforms: commaList(args.platforms)?.map((item) => enumValue(item) ?? item),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n currency: typeof args.currency === \"string\" && args.currency.trim() !== \"\" ? args.currency.trim() : undefined,\n };\n}\n\nfunction share(part: number, total: number): number | null {\n return total > 0 ? part / total : null;\n}\n\n/** \"2 of 6 health checks need a person: …\", or that none does. */\nfunction healthHeadline(checks: AdPerformanceHealthData[\"checks\"]): string {\n const asking = checks.filter((check) => check.state === \"act\" || check.state === \"look\");\n if (asking.length === 0) return `None of ${checks.length} health checks needs a person.`;\n return `${asking.length} of ${checks.length} health checks need a person: ${asking.map((check) => check.title).join(\", \")}.`;\n}\n\n/** The checklist and the headline numbers; the tables stay behind --full. */\nexport function compactHealth(data: AdPerformanceHealthData): Record<string, unknown> {\n return roundDeep({\n headline: healthHeadline(data.checks),\n checks: data.checks.map(({ section, state, line, window }) => ({ section, state, line, window })),\n asOf: data.asOf,\n spend: data.spend.map((row) => ({\n platform: row.platform,\n currency: row.currency,\n thisMonth: row.thisMonth.spend,\n lastMonthSameDays: row.lastMonth.spend,\n change: row.change,\n })),\n costPerResult: data.costPerResult.map((row) => ({\n platform: row.platform,\n currency: row.currency,\n last7Settled: row.current.costPerResult,\n prior7: row.previous.costPerResult,\n change: row.change,\n settledThrough: row.current.to,\n })),\n traffic30d: data.traffic.map((row) => ({\n platform: row.platform,\n currency: row.currency,\n costPerLinkClick: row.costPerLinkClick,\n linkCtr: row.linkCtr,\n cpm: row.cpm,\n })),\n learning7d: data.learning.map((row) => ({\n platform: row.platform,\n currency: row.currency,\n share: row.share,\n verdict: row.verdict,\n learningSpend: row.learningSpend + row.limitedSpend,\n totalSpend: row.totalSpend,\n inLearning: row.groups.length,\n })),\n audience30d: data.audience.map((row) => ({\n platform: row.platform,\n currency: row.currency,\n prospecting: share(row.prospectingSpend, row.totalSpend),\n retargeting: share(row.retargetingSpend, row.totalSpend),\n ...(row.unknownSpend > 0 ? { notReadYet: share(row.unknownSpend, row.totalSpend) } : {}),\n ...(row.segmentShares ? { segments: row.segmentShares } : {}),\n topExclusions: row.topExclusions.slice(0, 3),\n })),\n copy: data.copy.map((row) => ({ platform: row.platform, maximized: row.maximized, of: row.ads.length })),\n frequency: data.frequency.map((row) => ({\n platform: row.platform,\n averageWeeklyFrequency: row.averageFrequency,\n averageFirstTimeRate: row.averageFirstTimeRate,\n weeks: row.weeks.filter((week) => !week.partial).length,\n })),\n monthly: data.monthly.map((row) => ({\n platform: row.platform,\n currency: row.currency,\n months: row.months.map((month) => ({\n month: month.month,\n spend: month.spend,\n costPerResult: month.costPerResult,\n ...(month.partial ? { partial: true } : {}),\n })),\n })),\n segments: data.segments.map((row) => ({\n platform: row.platform,\n currency: row.currency,\n lastWeek: row.weeks\n .filter((week) => !week.partial)\n .at(-1)\n ?.segments.map((cell) => ({\n segment: cell.segment,\n share: cell.share,\n costPerResult: cell.costPerResult,\n })),\n moving: row.moving,\n })),\n unavailable: data.unavailable,\n });\n}\n\nconst LEARNING_ADVICE = {\n monitor: \"avoid more big edits (budget jumps, new targeting, new ads) until it settles\",\n act: \"consolidate ad sets or slow new launches so fewer of them restart learning\",\n} as const;\n\nexport function healthHints(data: AdPerformanceHealthData): string[] {\n const hints: string[] = [];\n for (const row of data.learning) {\n if (row.verdict !== \"monitor\" && row.verdict !== \"act\") continue;\n const where =\n row.basis === \"campaign\"\n ? \"campaigns whose bidding is still learning or held back by too little conversion data\"\n : \"ad sets still learning or learning-limited\";\n hints.push(\n `${Math.round((row.share ?? 0) * 100)}% of ${row.platform}'s last-7-day spend (${row.currency}) is in ${where} (healthy below ${AD_LEARNING_SHARE_THRESHOLDS.monitor * 100}%): ${LEARNING_ADVICE[row.verdict]}. --full lists them.`,\n );\n }\n for (const row of data.copy) {\n if (row.maximized < row.ads.length) {\n hints.push(\n `${row.ads.length - row.maximized} of the top ${row.ads.length} ${row.platform} ads leave copy slots empty (up to ${AD_COPY_VARIANTS_MAX} primary texts and ${AD_COPY_VARIANTS_MAX} headlines): more variants give delivery more to test. --full lists the counts.`,\n );\n }\n }\n for (const row of data.segments) if (row.moving) hints.push(row.moving);\n hints.push(\n \"Cost per result compares each platform's last 7 settled days; reach of several ad accounts is added. Money is in the reporting currency (--currency); never add amounts across currencies.\",\n );\n return hints;\n}\n\n// --- command ---\n\nregisterSchema({\n command: \"ads.performance.health\",\n description:\n \"An ad account's health from Baker's stored ad data. headline + checks: one verdict per section (act, look, ok, info = read but not judged, unavailable), problems first — the same checklist Measure → Ads → Summary shows under \\\"More about these accounts\\\". spend: this month so far vs the same days last month. costPerResult: last 7 settled days vs the 7 before. traffic30d: cost per link click, link CTR, CPM. learning7d: share of the last 7 days' spend in ad sets (Meta) or campaigns (Google Ads) still learning or learning-limited; verdict healthy <20%, monitor 20–50%, act >50%. audience30d (Meta): spend on prospecting (broad, interests, lookalikes) vs retargeting (site, engagement or customer-list audiences), Advantage+ customer segments where set up, most-excluded audiences. copy (Meta): top 10 ads by 30-day spend using all 5 primary texts and 5 headlines. frequency (Meta): average weekly frequency (impressions ÷ people reached) and first-time impression rate (reach ÷ impressions) over 12 whole weeks. monthly: spend and cost per result for 6 months. segments (Meta): weekly share of spend, cost per result and return by new / engaged / existing customers. unavailable says what a platform cannot fill and why. --full returns every table.\",\n args: HEALTH_ARGS as Parameters<typeof registerSchema>[0][\"args\"],\n});\n\nexport const healthCommand = defineCommand({\n meta: {\n name: \"health\",\n description:\n \"An ad account's health: spend, cost per result, learning, audiences, copy, frequency. Example: baker ads performance health --platforms meta\",\n },\n args: HEALTH_ARGS,\n run: async ({ args }) => {\n const empty = emptyFlagIssues(args, HEALTH_ARGS);\n if (empty.length > 0) failInvalid(empty, HEALTH_ARGS);\n const parsed = adPerformanceHealthRequestSchema.safeParse(healthInput(args));\n if (!parsed.success) failInvalid(parsed.error.issues, HEALTH_ARGS);\n try {\n const response = await postRead<AdPerformanceHealthData>(\"health\", parsed.data);\n const hints = healthHints(response.data);\n const data = args.full === true ? response.data : compactHealth(response.data);\n writeJson({ ok: true, data, ...(hints.length > 0 ? { hints } : {}) });\n } catch (err) {\n failRead(err);\n }\n },\n});\n","/**\n * `baker ads performance live-in` — which live campaigns use a landing (send\n * people to it) or a creative (show it in an ad). Read from Baker's synced ad\n * data; asked before changing either, because the change reaches them.\n */\n\nimport {\n type AdPerformanceLiveInData,\n type AdPerformanceLiveInRequest,\n adPerformanceLiveInRequestSchema,\n type LiveInCreative,\n type LiveInLanding,\n} from \"@baker/api/ads-performance\";\nimport { optionalString } from \"./args.ts\";\nimport { report } from \"./reportCommand.ts\";\n\nconst LIVE_IN_ARGS = {\n landing: { type: \"string\", description: \"Only this landing: its slug (src/pages/<slug>/)\", required: false },\n creative: { type: \"string\", description: \"Only this creative: its slug (src/creatives/<slug>/)\", required: false },\n full: {\n type: \"boolean\",\n description: \"Every live ad showing a creative, with its ad group and version\",\n required: false,\n default: false,\n },\n} as const;\n\nconst plural = (count: number, word: string) => `${count} ${word}${count === 1 ? \"\" : \"s\"}`;\n\nfunction compactLanding(landing: LiveInLanding) {\n return {\n slug: landing.slug,\n campaigns: landing.campaigns.map((campaign) => ({\n platform: campaign.platform,\n id: campaign.campaignId,\n name: campaign.name,\n ...(campaign.ads > 0 ? { ads: campaign.ads } : {}),\n ...(campaign.assetGroups > 0 ? { assetGroups: campaign.assetGroups } : {}),\n ...(campaign.keywords > 0 ? { keywords: campaign.keywords } : {}),\n spend30d: campaign.spend30d,\n })),\n };\n}\n\nfunction compactCreative(creative: LiveInCreative) {\n return {\n slug: creative.slug,\n title: creative.title,\n liveAds: creative.liveAds,\n ...(creative.versions.length > 0 ? { versions: creative.versions } : {}),\n ...(creative.likely ? { likely: true } : {}),\n campaigns: creative.campaigns.map((campaign) => ({\n platform: campaign.platform,\n id: campaign.campaignId,\n name: campaign.name,\n ads: campaign.ads.length,\n })),\n spend30d: creative.spend30d,\n };\n}\n\nexport function compactLiveIn(data: AdPerformanceLiveInData) {\n return { landings: data.landings.map(compactLanding), creatives: data.creatives.map(compactCreative) };\n}\n\nfunction landingHint(landing: LiveInLanding): string {\n const [first] = landing.campaigns;\n if (!first) return `No live campaign sends people to ${landing.slug} now: changing it touches no running ad.`;\n const count = landing.campaigns.length;\n return `${plural(count, \"live campaign\")} ${count === 1 ? \"sends\" : \"send\"} people to ${landing.slug}: changing the page changes what ${count === 1 ? \"its\" : \"their\"} visitors see once you publish. Read ${count === 1 ? \"it\" : \"them\"} first (baker ads performance entity ${first.campaignId} --platform ${first.platform} --level campaign) and name ${count === 1 ? \"it\" : \"them\"} to the person.`;\n}\n\nfunction creativeHint(creative: LiveInCreative): string {\n if (creative.liveAds === 0)\n return `No live ad shows ${creative.slug} now: a new version of it touches no running ad.`;\n const platforms = creative.platforms.map((platform) => `baker ads ${platform}`).join(\" / \");\n return `${creative.slug} runs in ${plural(creative.liveAds, \"live ad\")} across ${plural(creative.campaigns.length, \"campaign\")}. A new version reaches them only when you stage it into those ads (${platforms}); judge the running one first with baker ads performance creatives (its row's madeInBaker names it).`;\n}\n\nexport function liveInHints(data: AdPerformanceLiveInData, request: AdPerformanceLiveInRequest): string[] {\n const hints: string[] = [];\n if (request.landing !== undefined) hints.push(...data.landings.map(landingHint));\n if (request.creative !== undefined) hints.push(...data.creatives.map(creativeHint));\n if (data.creatives.some((creative) => creative.likely))\n hints.push('likely: some ads show a close look-alike, not the same file. Say \"likely runs in\".');\n if (request.landing === undefined && request.creative === undefined) {\n if (data.landings.length === 0 && data.creatives.length === 0)\n hints.push(\n \"No landing or creative is in a live campaign now. If ads were launched in the last hours, check baker ads performance status.\",\n );\n else\n hints.push(\n \"Before changing a landing or creative listed here, tell the person which live campaigns it reaches. --landing <slug> or --creative <slug> for one.\",\n );\n }\n return hints;\n}\n\nexport const liveInCommand = report<typeof adPerformanceLiveInRequestSchema, AdPerformanceLiveInData>({\n name: \"live-in\",\n schemaName: \"liveIn\",\n schemaDescription:\n \"Which live campaigns use a landing or a creative. Ask it before changing either. --landing <slug>: the live ads, Performance Max asset groups and keywords sending people to that page, per campaign, with 30 days of spend. --creative <slug>: the live ads showing that creative (any of its versions, matched by picture), per campaign, with the versions they show; likely: a close look-alike rather than the same file. Neither flag: every landing and creative that is live now. Read from Baker's synced ad data, refreshed every few hours; no platform call. --full lists every live ad of a creative.\",\n help: \"Which live campaigns use a landing or a creative. Example: baker ads performance live-in --landing demo\",\n path: \"live-in\",\n args: LIVE_IN_ARGS,\n request: adPerformanceLiveInRequestSchema,\n input: (args) => ({ landing: optionalString(args.landing), creative: optionalString(args.creative) }),\n compact: compactLiveIn,\n hints: liveInHints,\n});\n","/**\n * `baker ads performance people | personas | ladder | persona-fields` — who\n * the ads brought, how far up the Company's own ladder they got, and who they\n * are, from Baker's stored visits and outcomes (`convex/adPerformance/people.ts`).\n * Read-only: the ladder is the company's Funnel (changed with `baker funnel`),\n * and persona answers are read from Form fields named for them.\n */\n\nimport {\n type AdPeopleData,\n type AdPeopleLadderData,\n type AdPeopleRow,\n type AdPersonaFieldsData,\n type AdPersonasData,\n adPeopleRequestSchema,\n adPeopleSettingsRequestSchema,\n adPersonasRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { type ArgsDef, defineCommand } from \"citty\";\nimport type { z } from \"zod\";\nimport { writeJson } from \"../../../output.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport {\n commaList,\n ENTITIES_ARGS,\n emptyFlagIssues,\n enumValue,\n optionalNumber,\n SCOPE_ARGS,\n scopeInput,\n} from \"./args.ts\";\nimport { entityPath, roundDeep, roundNumber } from \"./report.ts\";\nimport { failInvalid, failRead, postRead } from \"./reportCommand.ts\";\n\n// --- pure: compact views and hints ---\n\nconst VOCABULARY_HINT =\n 'Say \"brought\" for --touch first and \"last paid touch\" for --touch last; each person counts once, for one entity. Never call it attributed revenue or ROI, and never add money across currencies.';\n\nfunction compactRow(row: AdPeopleRow, level: AdPeopleData[\"level\"]): Record<string, unknown> {\n const deals = row.companyDeals.opened + row.companyDeals.won > 0 ? { companyDeals: roundDeep(row.companyDeals) } : {};\n const path = row.entityId === \"\" ? null : entityPath({ ...row, level });\n return {\n platform: row.platform,\n ...(row.entityId === \"\" ? { untagged: true } : { entityId: row.entityId, name: row.name }),\n ...(path ? { path } : {}),\n ...(row.entityId !== \"\" && !row.known ? { unknownId: true } : {}),\n ...(row.spend > 0 ? { spend: roundNumber(row.spend), currency: row.currency } : {}),\n paidSessions: row.paidSessions,\n people: row.people,\n steps: row.stages.map((stage) => ({\n name: stage.name,\n people: stage.people,\n ...(stage.perLead === null ? {} : { perLead: roundNumber(stage.perLead) }),\n ...(stage.costPer === null ? {} : { costPer: roundNumber(stage.costPer) }),\n ...(stage.value.length > 0 ? { value: roundDeep(stage.value) } : {}),\n ...(stage.medianDays === null ? {} : { medianDays: roundNumber(stage.medianDays) }),\n })),\n ...deals,\n };\n}\n\nexport function compactPeople(data: AdPeopleData): Record<string, unknown> {\n if (!data.collected) return { collected: false, reason: data.notCollectedReason };\n return {\n window: data.window,\n level: data.level,\n touch: data.touch,\n ladder: data.ladder.stages.map((stage) => stage.name),\n rows: data.rows.map((row) => compactRow(row, data.level)),\n untagged: data.untagged.map((row) => compactRow(row, data.level)),\n coverage: roundDeep(data.coverage),\n maturity: data.maturity.map((step) => ({\n name: step.name,\n p75Days: step.p75Days === null ? null : roundNumber(step.p75Days),\n maturingFrom: step.maturingFrom,\n })),\n };\n}\n\nexport function peopleHints(data: AdPeopleData): string[] {\n if (!data.collected) return [data.notCollectedReason ?? \"People-level data is not collected for this company.\"];\n const hints: string[] = [VOCABULARY_HINT];\n if (data.windowClipped) {\n hints.push(\n `Visits are kept 400 days and a first touch is looked for 90 days before the window, so this covers ${data.window.from} to ${data.window.to}.`,\n );\n }\n if (data.ladder.isDefault) {\n hints.push(\n \"The ladder is the default (Lead = gave an email or phone, Customer = an amount from a CRM or the company's server) because the company's Funnel names no event after a visit. Run `baker ads performance ladder` to see which events could move people onto its lead and later steps; adding them to the Funnel (`baker funnel`) makes them this ladder.\",\n );\n }\n for (const step of data.maturity) {\n if (step.maturingFrom !== null && step.maturingFrom <= data.window.to && step.index > 1) {\n hints.push(\n `People who arrived from ${step.maturingFrom} on have not had the usual ${Math.ceil(step.p75Days ?? 0)} days to reach \"${step.name}\"; read their numbers as early, not as failing.`,\n );\n }\n }\n const { resolvedShare, paidTouchShare } = data.coverage;\n if (resolvedShare !== null && data.coverage.paidSessions >= 20 && resolvedShare < 0.8) {\n hints.push(\n `Only ${Math.round(resolvedShare * 100)}% of paid visits carry an id that names a synced campaign, ad set or ad; the rest show under untagged (or unknownId). Check \\`baker ads performance tracking\\`.`,\n );\n }\n if (paidTouchShare !== null && data.coverage.leads >= 10) {\n hints.push(\n `${Math.round(paidTouchShare * 100)}% of the window's ${data.coverage.leads} leads had a paid visit in the 90 days before; the others came another way.`,\n );\n }\n return hints;\n}\n\nexport function compactPersonas(data: AdPersonasData): Record<string, unknown> {\n if (!data.collected) return { collected: false, reason: data.notCollectedReason };\n return {\n window: data.window,\n level: data.level,\n touch: data.touch,\n dimension: data.dimension,\n fieldKeys: data.fieldKeys,\n ladder: data.ladderStages,\n rows: data.rows.map((row) => ({\n platform: row.platform,\n ...(row.entityId === \"\" ? { untagged: true } : { entityId: row.entityId, name: row.name }),\n people: row.people,\n values: row.values.map((value) => ({\n value: value.kind === \"answer\" ? value.value : value.kind === \"other\" ? \"(other answers)\" : \"(no answer)\",\n people: value.people,\n steps: value.stagePeople,\n })),\n })),\n };\n}\n\nexport function personasHints(data: AdPersonasData): string[] {\n if (!data.collected) return [data.notCollectedReason ?? \"People-level data is not collected for this company.\"];\n const hints: string[] = [];\n if (data.fieldKeys.length === 0 && ![\"email_kind\", \"visit_country\", \"device\"].includes(data.dimension)) {\n hints.push(\n `No Form field is known to answer \"${data.dimension}\". Run \\`baker ads performance persona-fields\\` to see the fields people answered; a Form field named for the question (job_title for role, company_size, industry…) is read automatically.`,\n );\n } else if (data.fieldsSuggested) {\n hints.push(`Read from ${data.fieldKeys.join(\", \")}, chosen from the field names.`);\n }\n if (data.dimension === \"email_kind\") {\n hints.push(\n \"A work address is recognised only when Baker keeps a copy of what visitors typed; otherwise it reads as personal.\",\n );\n }\n hints.push(\n \"steps are people per ladder step, the lead first. Answers fewer than three people gave are folded into (other answers), so no value points at one person.\",\n );\n return hints;\n}\n\nexport function ladderHints(data: AdPeopleLadderData): string[] {\n return [\n data.ladder.isDefault\n ? \"The company's Funnel names no event after a visit, so the default is in force. Suggest which of these events move people onto the Funnel's lead and later steps; adding them to the Funnel (`baker funnel`) makes them the ladder.\"\n : \"This ladder is the company's Funnel: its first step after a visit is the lead and later steps follow in order (steps at the same point are one rung; at most four, keeping the step where money arrives). To change it, change the Funnel (`baker funnel`).\",\n \"A HubSpot Source's stage values can narrow a step: <member>|hubspot_value=<value>.\",\n ];\n}\n\nexport function personaFieldsHints(data: AdPersonaFieldsData): string[] {\n return [\n data.suggested\n ? \"This map is Baker's reading of the Form field names (job_title → role, company_size, industry…); a field named for a question is read for it.\"\n : \"This is the company's stored persona map.\",\n \"Fields whose answers are mostly kept sealed (masked) identify people and are never a persona.\",\n ];\n}\n\n// --- commands ---\n\nconst LEVEL_ARGS = {\n level: { type: \"string\", description: \"campaign (default), ad_group or ad\", required: false },\n touch: {\n type: \"string\",\n description: \"last (default: the last paid touch before they became a lead) or first (what brought them)\",\n required: false,\n },\n} as const;\n\nconst PEOPLE_ARGS = {\n ...SCOPE_ARGS,\n \"ad-group-ids\": ENTITIES_ARGS[\"ad-group-ids\"],\n ...LEVEL_ARGS,\n limit: { type: \"string\", description: \"Entities to return, 1-500 (default 50)\", required: false },\n} as const;\n\nconst PERSONAS_ARGS = {\n ...SCOPE_ARGS,\n \"ad-group-ids\": ENTITIES_ARGS[\"ad-group-ids\"],\n ...LEVEL_ARGS,\n dimension: {\n type: \"string\",\n description:\n \"role, seniority, company_size, industry, use_case, heard_from, budget, country (from Form answers), or email_kind, visit_country, device\",\n required: true,\n },\n top: {\n type: \"string\",\n description: \"Answers to name before the rest read other, 1-30 (default 12)\",\n required: false,\n },\n} as const;\n\nconst SETTINGS_ARGS = {\n days: { type: \"string\", description: \"How far back to look, 7-300 (default 90)\", required: false },\n full: SCOPE_ARGS.full,\n} as const;\n\ntype Args = Record<string, unknown>;\n\ninterface PeopleCommandSpec<S extends z.ZodType, D> {\n name: string;\n schemaName: string;\n schemaDescription: string;\n help: string;\n path: string;\n args: ArgsDef;\n request: S;\n input: (args: Args) => unknown;\n compact: (data: D) => unknown;\n hints: (data: D) => string[];\n}\n\nfunction peopleCommand<S extends z.ZodType, D>(spec: PeopleCommandSpec<S, D>) {\n registerSchema({\n command: `ads.performance.${spec.schemaName}`,\n description: spec.schemaDescription,\n args: spec.args as Parameters<typeof registerSchema>[0][\"args\"],\n });\n return defineCommand({\n meta: { name: spec.name, description: spec.help },\n args: spec.args,\n run: async ({ args }) => {\n const empty = emptyFlagIssues(args, spec.args);\n if (empty.length > 0) failInvalid(empty, spec.args);\n const parsed = spec.request.safeParse(spec.input(args));\n if (!parsed.success) failInvalid(parsed.error.issues, spec.args);\n try {\n const response = await postRead<D>(spec.path, parsed.data);\n const hints = spec.hints(response.data);\n const data = args.full === true ? response.data : spec.compact(response.data);\n writeJson({ ok: true, data, ...(hints.length > 0 ? { hints } : {}) });\n } catch (err) {\n failRead(err);\n }\n },\n });\n}\n\nconst PEOPLE_NOTE =\n \"One person counts once, for one entity (--touch last: the last paid visit before they became a lead; first: the visit that brought them), and their later steps count when they happen within 90 days of it. Steps are the company's own ladder. Money in the reporting currency (--currency), never added across currencies. --full returns every field.\";\n\nconst levelTouchInput = (args: Args) => ({\n ...scopeInput(args),\n adGroupIds: commaList(args[\"ad-group-ids\"]),\n level: enumValue(args.level),\n touch: enumValue(args.touch),\n});\n\nexport const peopleOutcomesCommand = peopleCommand<typeof adPeopleRequestSchema, AdPeopleData>({\n name: \"people\",\n schemaName: \"people\",\n schemaDescription: `Who each campaign, ad set or ad brought and how far they got: paid visits, people, and per ladder step (lead, then e.g. qualified, customer) the people, the share of leads, the cost per person, the value per currency and the median days to it; untagged paid traffic per platform; coverage (paid visits tied to an ad, leads with a known paid visit); and when recent cohorts are still maturing. ${PEOPLE_NOTE}`,\n help: \"People each campaign brought and how far they got. Example: baker ads performance people --level campaign --days 90. Inside one campaign: --level ad_group --campaign-ids <id>; inside one ad set: --level ad --ad-group-ids <id>\",\n path: \"people\",\n args: PEOPLE_ARGS,\n request: adPeopleRequestSchema,\n input: (args) => ({ ...levelTouchInput(args), limit: optionalNumber(args.limit) }),\n compact: compactPeople,\n hints: peopleHints,\n});\n\nexport const personasCommand = peopleCommand<typeof adPersonasRequestSchema, AdPersonasData>({\n name: \"personas\",\n schemaName: \"personas\",\n schemaDescription: `Who the ads brought, split by one persona question — role, company size, industry… from the company's Form answers, or work vs personal address, the visit's country or device — with how many of each reached each ladder step: \"which roles from this campaign become customers\". Answers fewer than three people gave read as other. ${PEOPLE_NOTE}`,\n help: \"People each campaign brought, by role, size, industry... Example: baker ads performance personas --dimension role\",\n path: \"personas\",\n args: PERSONAS_ARGS,\n request: adPersonasRequestSchema,\n input: (args) => ({\n ...levelTouchInput(args),\n dimension: enumValue(args.dimension),\n top: optionalNumber(args.top),\n }),\n compact: compactPersonas,\n hints: personasHints,\n});\n\nexport const ladderCommand = peopleCommand<typeof adPeopleSettingsRequestSchema, AdPeopleLadderData>({\n name: \"ladder\",\n schemaName: \"ladder\",\n schemaDescription:\n \"The company's lead-to-customer ladder in force, read off its Funnel (default when the Funnel names no event after a visit: Lead = gave an email or phone, Customer = an amount from a CRM or the company's server), and every event it could be made of from the last --days: Form steps, page events, HubSpot Source events with their stage values, with people per event and the step each counts for now. Read-only; the ladder is the company's Funnel, changed with `baker funnel`.\",\n help: \"The lead-to-customer steps and what they can be made of. Example: baker ads performance ladder\",\n path: \"ladder\",\n args: SETTINGS_ARGS,\n request: adPeopleSettingsRequestSchema,\n input: (args) => ({ days: optionalNumber(args.days) }),\n compact: roundDeep,\n hints: ladderHints,\n});\n\nexport const personaFieldsCommand = peopleCommand<typeof adPeopleSettingsRequestSchema, AdPersonaFieldsData>({\n name: \"persona-fields\",\n schemaName: \"personaFields\",\n schemaDescription:\n \"Which Form fields answer which persona question (role, seniority, company_size, industry, use_case, heard_from, budget, country) — the company's map, else Baker's suggestion from the field names — and every field people answered in the last --days with its common answers and how often it was kept sealed. Read-only.\",\n help: \"Which Form fields say who people are. Example: baker ads performance persona-fields\",\n path: \"persona-fields\",\n args: SETTINGS_ARGS,\n request: adPeopleSettingsRequestSchema,\n input: (args) => ({ days: optionalNumber(args.days) }),\n compact: roundDeep,\n hints: personaFieldsHints,\n});\n","/**\n * `baker ads performance progress | diagnose | pulse` — the pure half: flags,\n * request mapping, the compact view and the hints. Is it really getting better\n * or worse, how sure, and why (`convex/adPerformance/diagnosis.ts`).\n */\n\nimport type {\n AdPerformanceDiagnosisData,\n AdPerformanceProgressData,\n AdPerformancePulseData,\n AdProgressRow,\n} from \"@baker/api/ads-performance\";\nimport {\n commaList,\n enumValue,\n ONE_ENTITY_SCOPE_ARGS,\n oneEntityScopeInput,\n optionalNumber,\n optionalString,\n SCOPE_ARGS,\n scopeInput,\n} from \"./args.ts\";\nimport { roundDeep, roundNumber } from \"./report.ts\";\n\n// --- flags ---\n\nexport const PROGRESS_ARGS = {\n ...SCOPE_ARGS,\n level: { type: \"string\", description: \"campaign (default), ad_group or ad\", required: false },\n status: {\n type: \"string\",\n description:\n \"Comma list: worsening,mixed,not_comparable,steady,improving,too_early,too_little_data,stopped (default all)\",\n required: false,\n },\n limit: { type: \"string\", description: \"Rows to return, worst first (default 25, at most 200)\", required: false },\n} as const;\n\nexport const DIAGNOSE_ARGS = {\n id: { type: \"positional\", description: \"The campaign, ad group or ad id\", required: true },\n platform: { type: \"string\", description: \"meta, google, linkedin, x or chatgpt\", required: true },\n level: { type: \"string\", description: \"campaign, ad_group or ad\", required: true },\n ...ONE_ENTITY_SCOPE_ARGS,\n} as const;\n\nexport const PULSE_ARGS = {\n platforms: SCOPE_ARGS.platforms,\n \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"],\n currency: SCOPE_ARGS.currency,\n full: SCOPE_ARGS.full,\n} as const;\n\ntype Args = Record<string, unknown>;\n\nexport function progressInput(args: Args) {\n return {\n ...scopeInput(args),\n level: enumValue(args.level),\n statuses: commaList(args.status)?.map((item) => enumValue(item) ?? item),\n limit: optionalNumber(args.limit),\n };\n}\n\nexport function diagnoseInput(args: Args) {\n return {\n ...oneEntityScopeInput(args),\n platform: enumValue(args.platform),\n level: enumValue(args.level),\n entityId: optionalString(args.id),\n };\n}\n\nexport function pulseInput(args: Args) {\n return {\n platforms: commaList(args.platforms)?.map((item) => enumValue(item) ?? item),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n currency: optionalString(args.currency),\n };\n}\n\n// --- compact ---\n\nfunction nullableRound(value: number | null): number | null {\n return value === null ? null : roundNumber(value);\n}\n\nfunction compactRow(row: AdProgressRow): Record<string, unknown> {\n return {\n platform: row.platform,\n level: row.level,\n entityId: row.entityId,\n name: row.name,\n status: row.status,\n ...(row.confidence ? { confidence: row.confidence } : {}),\n ...(row.judged\n ? {\n judged: {\n metric: row.judged.metric,\n recent: nullableRound(row.judged.recent),\n baseline: nullableRound(row.judged.baseline),\n changePct: nullableRound(row.judged.changePct),\n ...(row.judged.fallbackFrom ? { fallbackFrom: row.judged.fallbackFrom } : {}),\n },\n }\n : {}),\n spend: roundNumber(row.spend),\n currency: row.currency,\n ...(row.atStake === null ? {} : { atStake: roundNumber(row.atStake) }),\n headline: row.headline,\n next: row.next,\n weekly: row.sparkline.map((point) => nullableRound(point.value)),\n };\n}\n\nexport function compactProgress(data: AdPerformanceProgressData): Record<string, unknown> {\n return {\n level: data.level,\n asOf: data.asOf.map((a) => ({ platform: a.platform, date: a.date })),\n counts: Object.fromEntries(Object.entries(data.counts).filter(([, n]) => n > 0)),\n rows: data.rows.map(compactRow),\n };\n}\n\nexport function compactDiagnosis(data: AdPerformanceDiagnosisData): Record<string, unknown> {\n if (data.entity === null || data.diagnosis === null) return { asOf: data.asOf, entity: null };\n const d = data.diagnosis;\n return {\n asOf: data.asOf,\n entity: data.entity,\n status: d.status,\n ...(d.confidence ? { confidence: d.confidence } : {}),\n headline: d.headline,\n next: d.next,\n judged: roundDeep(d.judged),\n windows: d.windows,\n spend: { recent: roundNumber(d.recentSpend), baseline: roundNumber(d.baselineSpend) },\n ...(d.atStake === null ? {} : { atStake: roundNumber(d.atStake) }),\n drivers: roundDeep(d.drivers),\n ...(d.marginal ? { marginal: roundDeep(d.marginal) } : {}),\n ...(d.impressionShare ? { impressionShare: roundDeep(d.impressionShare) } : {}),\n findings: d.findings.map((f) => ({\n lens: f.lens,\n effect: f.effect,\n sentence: f.sentence,\n check: f.check,\n ...(f.command ? { command: f.command } : {}),\n })),\n weekly: data.trajectory.map((p) => ({\n weekEnd: p.weekEnd,\n value: nullableRound(p.value),\n spend: roundNumber(p.spend),\n })),\n milestones: data.milestones.map((m) => ({ day: m.day, label: m.label })),\n };\n}\n\nexport function compactPulse(data: AdPerformancePulseData): Record<string, unknown> {\n return {\n rows: data.rows.map((row) => {\n const { platform, adAccountId, currency, day, ...metrics } = row;\n return {\n platform,\n adAccountId,\n currency,\n day,\n metrics: Object.fromEntries(\n Object.entries(metrics).map(([name, m]) => [\n name,\n { value: nullableRound(m.value), mean: nullableRound(m.mean), ...(m.watch ? { watch: true } : {}) },\n ]),\n ),\n };\n }),\n };\n}\n\n// --- hints ---\n\nconst METRIC_WORDS: Record<string, string> = {\n result_value_per_spend: \"return on ad spend\",\n cost_per_result: \"cost per result\",\n cost_per_visit: \"cost per landing visit\",\n cost_per_link_click: \"cost per click\",\n cost_per_video_view: \"cost per video view\",\n cost_per_engagement: \"cost per engagement\",\n cpm: \"cost per 1,000 impressions\",\n};\n\nconst SAY_IT =\n \"Report the status with its confidence and the headline's reason; never call a number worse on its own, and never add money across currencies.\";\n\nexport function progressHints(data: AdPerformanceProgressData): string[] {\n const hints: string[] = [SAY_IT];\n for (const row of data.rows.filter((r) => r.status === \"not_comparable\").slice(0, 3)) {\n hints.push(`\"${row.name}\" is not_comparable: its goal or how results are counted changed. ${row.next}`);\n }\n const fallbacks = data.rows.filter((r) => r.judged?.fallbackFrom);\n if (fallbacks.length > 0) {\n const sample = fallbacks[0];\n hints.push(\n `${fallbacks.length} row(s) are judged on an upstream metric (e.g. \"${sample?.name}\" on ${METRIC_WORDS[sample?.judged?.metric ?? \"\"] ?? \"clicks\"}): too few results to judge them on results. Say so.`,\n );\n }\n if (data.rows.some((r) => r.status === \"worsening\")) {\n hints.push(\n \"Start with the worsening rows: `baker ads performance diagnose <id> --platform <p> --level <l>` shows why, with what to check.\",\n );\n }\n return hints;\n}\n\nexport function diagnosisHints(\n data: AdPerformanceDiagnosisData,\n request: { entityId: string; level: string; platform: string },\n): string[] {\n if (data.entity === null) {\n return [\n `No ${request.level} ${request.entityId} delivered on ${request.platform} in the six settled weeks before ${data.asOf}. Check the id with \\`baker ads performance entities --level ${request.level} --include-idle\\`, or name a window that ends on a day it ran: \\`baker ads performance diagnose ${request.entityId} --platform ${request.platform} --level ${request.level} --start YYYY-MM-DD --end YYYY-MM-DD\\`.`,\n ];\n }\n const status = data.diagnosis?.status;\n if (status === \"not_comparable\") return [`Not comparable with before: ${data.diagnosis?.next ?? \"\"}`];\n if (status === \"too_early\" || status === \"too_little_data\")\n return [\"Do not change it on these numbers; say when to look again.\"];\n return [SAY_IT];\n}\n\nexport function pulseHints(data: AdPerformancePulseData): string[] {\n const watched = data.rows.flatMap((row) =>\n Object.entries(row)\n .filter(([, m]) => typeof m === \"object\" && m !== null && \"watch\" in m && m.watch === true)\n .map(([name]) => `${row.platform} ${row.adAccountId} ${name} on ${row.day}`),\n );\n return watched.length > 0\n ? [\n `Outside the usual range of the 7 days before: ${watched.join(\"; \")}. One day is a signal to look, not a verdict.`,\n ]\n : [];\n}\n","/**\n * `baker ads performance brand-split | impression-share | keyword-quality |\n * google-report | budgets | segments` — the Google Search reads, and the\n * staged changes to what decides them (brand and competitor names, a\n * campaign's or a search term's segment, a segment's target, a monthly\n * budget). Reads are compact by default (`--full` for everything); every\n * write stages on this chat and applies when the person publishes it.\n */\n\nimport {\n type AdBrandSplitSegment,\n type AdBudgetPacingRow,\n type AdKeywordQualityRow,\n type AdPerformanceBrandSplitData,\n type AdPerformanceBudgetsData,\n type AdPerformanceGoogleReportData,\n type AdPerformanceImpressionShareData,\n type AdPerformanceKeywordQualityData,\n type AdPerformanceSearchTermsData,\n type AdPerformanceSegmentsData,\n type AdSearchTermRow,\n adPerformanceBrandSplitRequestSchema,\n adPerformanceBudgetsRequestSchema,\n adPerformanceBudgetsSetRequestSchema,\n adPerformanceGoogleReportRequestSchema,\n adPerformanceImpressionShareRequestSchema,\n adPerformanceKeywordQualityRequestSchema,\n adPerformanceSegmentsRequestSchema,\n adPerformanceSegmentsSetRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { commaList, enumValue, optionalNumber, PACING_ARGS, pacingInput, SCOPE_ARGS, scopeInput } from \"./args.ts\";\nimport { withWrites, writeCommand } from \"./goalWrites.ts\";\nimport { compactEntityRow, pagingHint, roundDeep, roundNumber } from \"./report.ts\";\nimport { report, STORE_NOTE } from \"./reportCommand.ts\";\n\ntype Args = Record<string, unknown>;\n\nconst round = (value: number | null) => (value === null ? null : roundNumber(value));\n\nconst money = (amount: number, currency: string) => `${roundNumber(amount)} ${currency}`;\n\n// --- compact views ---\n\nfunction compactSegment(row: AdBrandSplitSegment): Record<string, unknown> {\n return {\n segment: row.segment,\n currency: row.currency,\n spend: roundNumber(row.metrics.spend),\n spendShare: round(row.spendShare),\n results: roundNumber(row.metrics.results),\n costPerResult: round(row.ratios.costPerResult),\n ...(row.metrics.resultValue > 0 ? { roas: round(row.ratios.resultValuePerSpend) } : {}),\n ctr: round(row.ratios.ctr),\n cpc: round(row.ratios.cpc),\n conversionRate: round(row.ratios.conversionRate),\n ...(row.ratios.impressionShare !== null ? { impressionShare: round(row.ratios.impressionShare) } : {}),\n ...(row.comparison\n ? {\n change: roundDeep({\n spend: row.comparison.deltas.spend,\n results: row.comparison.deltas.results,\n costPerResult: row.comparison.deltas.costPerResult,\n conversionRate: row.comparison.deltas.conversionRate,\n impressionSharePoints: row.comparison.impressionSharePoints,\n }),\n }\n : {}),\n ...(row.target\n ? {\n target: {\n ...roundDeep({ metric: row.target.metric, value: row.target.value }),\n source: row.target.source,\n },\n }\n : {}),\n status: row.status,\n };\n}\n\n/** A search term as a negative-keyword decision needs it: where it was bought, what it cost and brought, how it was read. */\nfunction compactTerm(row: AdSearchTermRow): Record<string, unknown> {\n return {\n searchTerm: row.searchTerm,\n matchType: row.matchType,\n keywordText: row.keywordText,\n ...(row.status !== \"\" && row.status !== \"NONE\" ? { status: row.status } : {}),\n campaignId: row.campaignId,\n campaignName: row.campaignName,\n adGroupId: row.adGroupId,\n adGroupName: row.adGroupName,\n termSegment: row.termSegment,\n campaignSegment: row.campaignSegment,\n currency: row.currency,\n spend: roundNumber(row.spend),\n clicks: row.clicks,\n conversions: roundNumber(row.conversions),\n ...(row.conversionValue > 0 ? { conversionValue: roundNumber(row.conversionValue) } : {}),\n costPerConversion: round(row.costPerConversion),\n ...(row.termUnsure ? { termUnsure: true } : {}),\n ...(row.termChosen ? { termChosen: true } : {}),\n };\n}\n\nexport function compactSearchTerms(data: AdPerformanceSearchTermsData): Record<string, unknown> {\n return { window: data.window, totalRows: data.totalRows, rows: data.rows.map(compactTerm) };\n}\n\nexport function searchTermsHints(\n data: AdPerformanceSearchTermsData,\n request: { offset: number; platforms?: readonly string[] },\n): string[] {\n const hints: string[] = [];\n if (request.platforms && !request.platforms.includes(\"google\"))\n hints.push(\"Search terms are Google Ads only: drop --platforms, or name google.\");\n const paging = pagingHint(data.totalRows, request.offset, data.rows.length);\n if (paging !== null) hints.push(paging);\n return hints;\n}\n\nexport function compactBrandSplit(data: AdPerformanceBrandSplitData): Record<string, unknown> {\n return {\n answer: data.answer.sentence,\n window: data.window,\n comparison: data.comparison,\n segments: data.segments.map(compactSegment),\n trend: data.trend.map((point) => ({\n month: point.bucket.slice(0, 7),\n segment: point.segment,\n currency: point.currency,\n spend: roundNumber(point.metrics.spend),\n results: roundNumber(point.metrics.results),\n costPerResult: round(point.ratios.costPerResult),\n ...(point.mature ? {} : { stillCounting: true }),\n })),\n leakage: {\n totalRows: data.leakage.totalRows,\n spend: roundDeep(data.leakage.spend),\n top: data.leakage.rows.slice(0, 10).map(compactTerm),\n },\n unsure: { totalRows: data.unsure.totalRows, top: data.unsure.rows.slice(0, 10).map(compactTerm) },\n ...(data.reviewed.count > 0 ? { reviewed: data.reviewed.count } : {}),\n names: data.names,\n ...(data.stillSorting ? { stillSorting: true } : {}),\n };\n}\n\nexport function brandSplitHints(data: AdPerformanceBrandSplitData): string[] {\n const hints: string[] = [\"Lead with answer: it is the question this read answers, in one line.\"];\n if (data.names.brandNamesDefault)\n hints.push(\n `Brand searches are judged against only the company's name and website (${data.names.brandNames.join(\", \")}). If it sells products under other names, add them: baker ads performance segments set --brand \"<names>\".`,\n );\n if (data.leakage.totalRows > 0)\n hints.push(\n `${data.leakage.totalRows} brand searches were bought by non-brand or competitor campaigns (${data.leakage.spend.map((s) => money(s.amount, s.currency)).join(\", \")}): brand traffic paid at non-brand prices, and it flatters their cost per result. Adding the brand as a negative keyword there sends it to the brand campaign (a staged Google Ads change). Above pocket change it is also an alert (rule brand_leak) in baker ads performance attention: claim it there, and mark it fixed once the negatives are staged.`,\n );\n if (data.unsure.totalRows > 0)\n hints.push(\n `${data.unsure.totalRows} search terms could be brand or not and nobody has answered them yet: list them with baker ads performance search-terms --unsure and settle each with baker ads performance segments set --term \"<term>\" --segment brand|competitor|non_brand. ${data.reviewed.count > 0 ? `${data.reviewed.count} were already answered by a person: do not ask about those again.` : \"\"}`.trim(),\n );\n if (data.stillSorting)\n hints.push(\n \"Some Search campaigns are still being sorted (segment unsorted): their spend joins brand, competitor or non-brand within the hour.\",\n );\n const nonBrand = data.segments.find((s) => s.segment === \"non_brand\");\n if (nonBrand && nonBrand.target?.source !== \"segment\")\n hints.push(\n `Non-brand has no target of its own, so it is ${nonBrand.target ? `judged against the ${nonBrand.target.source === \"company\" ? \"company default\" : `${nonBrand.target.source} target`}` : \"not judged\"}: ask the person what a new customer from search may cost, then baker ads performance segments set --target non_brand --cost <amount> --currency <ISO>.`,\n );\n return hints;\n}\n\nexport function compactImpressionShare(data: AdPerformanceImpressionShareData): Record<string, unknown> {\n return {\n window: data.window,\n comparison: data.comparison,\n topMeasuredFrom: data.topMeasuredFrom,\n campaigns: data.campaigns.map((row) =>\n roundDeep({\n adAccountId: row.adAccountId,\n campaignId: row.campaignId,\n name: row.name,\n segment: row.segment,\n bidStrategy: row.bidStrategy,\n currency: row.currency,\n spend: row.spend,\n results: row.results,\n now: row.now,\n ...(row.points ? { points: row.points } : {}),\n ...(row.limitedBy ? { limitedBy: row.limitedBy } : {}),\n ...(row.sharePrimary ? { sharePrimary: true } : {}),\n }),\n ),\n };\n}\n\nexport function impressionShareHints(data: AdPerformanceImpressionShareData): string[] {\n const hints: string[] = [];\n const budget = data.campaigns.filter((row) => row.limitedBy === \"budget\");\n const rank = data.campaigns.filter((row) => row.limitedBy === \"rank\");\n if (budget.length > 0)\n hints.push(\n `Held back by budget: ${budget.map((row) => row.name).join(\", \")}. More budget buys the searches they miss — check which earn it with baker ads performance budget-recommendations before raising any.`,\n );\n if (rank.length > 0)\n hints.push(\n `Held back by ad rank (bids and quality): ${rank.map((row) => row.name).join(\", \")}. Budget will not fix it; look at bids, ad relevance and landing pages (baker ads performance keyword-quality).`,\n );\n if (data.topMeasuredFrom && data.topMeasuredFrom > data.window.from)\n hints.push(\n `Top-of-page rates are measured from ${data.topMeasuredFrom}; earlier days of the window have none, so they read the days since.`,\n );\n if (data.campaigns.some((row) => !row.sharePrimary))\n hints.push(\n \"Impression share is the goal only for campaigns bidding for it (TARGET_IMPRESSION_SHARE); for the rest it explains volume, it is not a target.\",\n );\n return hints;\n}\n\nfunction compactKeyword(row: AdKeywordQualityRow): Record<string, unknown> {\n return {\n keyword: row.name,\n campaignName: row.campaignName,\n adGroupName: row.adGroupName,\n qualityScore: row.qualityScore,\n expectedCtr: row.expectedCtr,\n adRelevance: row.adRelevance,\n landingPageExperience: row.landingPageExperience,\n ...(row.page ? { page: `${row.page.host}${row.page.path}`, bakerPage: row.page.baker } : {}),\n currency: row.currency,\n spend: roundNumber(row.spend),\n clicks: row.clicks,\n results: roundNumber(row.results),\n };\n}\n\nexport function compactKeywordQuality(data: AdPerformanceKeywordQualityData): Record<string, unknown> {\n return {\n window: data.window,\n summary: roundDeep(data.summary),\n landings: roundDeep(data.landings.slice(0, 15)),\n keywords: data.rows.map(compactKeyword),\n totalRows: data.totalRows,\n };\n}\n\nexport function keywordQualityHints(data: AdPerformanceKeywordQualityData): string[] {\n const weakBaker = data.landings.filter((page) => page.baker && page.belowAverageSpend > 0);\n const weakOther = data.landings.filter((page) => !page.baker && page.belowAverageSpend > 0);\n const hints: string[] = [];\n if (data.totalRows > data.rows.length)\n hints.push(\n `summary and landings add up the top ${data.rows.length} keywords by spend of ${data.totalRows}, not all of them: say so, or read more with --limit (up to 1000).`,\n );\n if (weakBaker.length > 0)\n hints.push(\n `Google rates the landing page experience below average on Baker pages: ${weakBaker\n .slice(0, 3)\n .map((page) => `${page.host}${page.path} (${money(page.belowAverageSpend, page.currency)})`)\n .join(\", \")}. Improve them: baker landing critique, then make the page answer what those keywords search for.`,\n );\n if (weakOther.length > 0)\n hints.push(\n `Pages Baker does not build also rate below average (${weakOther.length}); a Baker landing matched to those keywords is one fix.`,\n );\n const weakCtr = data.summary.some((s) => s.belowAverage.expectedCtr > 0);\n if (weakCtr)\n hints.push(\n \"Below-average expected click rate means the ads do not match what people search: tighten the ad groups' headlines to the keywords.\",\n );\n return hints;\n}\n\nexport function compactGoogleReport(data: AdPerformanceGoogleReportData): Record<string, unknown> {\n return {\n window: data.window,\n snapshot: roundDeep(\n data.snapshot.map((s) => ({\n currency: s.currency,\n metrics: s.metrics,\n ratios: s.ratios,\n ...(s.comparison ? { change: s.comparison.deltas } : {}),\n })),\n ),\n budgets: data.budgets ? compactBudgets(data.budgets) : null,\n brandSplit: compactBrandSplit(data.brandSplit),\n byCampaignType: data.byCampaignType.map((point) => ({\n month: point.bucket.slice(0, 7),\n type: point.groupKey,\n currency: point.currency,\n spend: roundNumber(point.metrics.spend),\n results: roundNumber(point.metrics.results),\n })),\n campaigns: data.campaigns.map(compactEntityRow),\n impressionShare: compactImpressionShare(data.impressionShare).campaigns,\n topAdGroups: data.topAdGroups.map(compactEntityRow),\n topKeywords: data.topKeywords.map(compactEntityRow),\n keywordQuality: roundDeep(data.keywordQuality),\n attention: data.attention.map((item) => ({\n tier: item.tier,\n title: item.title,\n detail: item.detail,\n ...(item.moneyAtStake !== null ? { moneyAtStake: roundNumber(item.moneyAtStake) } : {}),\n })),\n };\n}\n\nexport function googleReportHints(data: AdPerformanceGoogleReportData): string[] {\n const stopped = data.campaigns.filter((row) => row.metrics.spend === 0 && (row.comparison?.previous.spend ?? 0) > 0);\n return [\n \"Write the report from these sections, each number labelled with where it comes from (reported by Google, seen on the site, from the CRM). Judge brand and non-brand apart: never blend their cost per result.\",\n ...(stopped.length > 0\n ? [\n `${stopped.length} campaigns spent in the period before and nothing now: check baker ads performance changes --entity-ids <id> for who paused them before calling it a drop.`,\n ]\n : []),\n ...brandSplitHints(data.brandSplit),\n ...impressionShareHints(data.impressionShare),\n ];\n}\n\n/** \"€2,430\": whole units, in the budget's currency. */\nfunction budgetMoney(amount: number, currency: string): string {\n return new Intl.NumberFormat(\"en-US\", { style: \"currency\", currency, maximumFractionDigits: 0 }).format(amount);\n}\n\n/** \"10 Oct\". */\nfunction shortDay(day: string): string {\n return new Date(`${day}T00:00:00Z`).toLocaleDateString(\"en-GB\", { day: \"numeric\", month: \"short\", timeZone: \"UTC\" });\n}\n\nconst STATUS_PHRASE: Record<AdBudgetPacingRow[\"status\"], string> = {\n on_track: \"on track\",\n will_underspend: \"will underspend\",\n will_run_out: \"will run out early\",\n over_budget: \"already over budget\",\n no_rate: \"no exchange rate converts the spend, so it is not judged\",\n};\n\n/** One sentence a person can be told as is: spent, planned by now, where the month ends, the verdict. */\nexport function budgetHeadline(row: AdBudgetPacingRow, asOf: string): string {\n const money = (amount: number) => budgetMoney(amount, row.budget.currency);\n if (row.spent === null) return `${row.label}: ${STATUS_PHRASE.no_rate}.`;\n const pace = row.projected === null ? \"\" : `; at the last 7 days' pace the month ends near ${money(row.projected)}`;\n const runsOut = row.runsOutOn ? ` around ${shortDay(row.runsOutOn)}` : \"\";\n return `${row.label}: ${money(row.spent)} of ${money(row.budget.amount)} spent by ${shortDay(asOf)}, against ${money(row.plannedByNow)} planned by then${pace} — ${STATUS_PHRASE[row.status]}${runsOut}.`;\n}\n\n/** A budget's amounts read in whole units: cents say nothing about a month's plan. */\nconst whole = (amount: number | null) => (amount === null ? null : Math.round(amount));\n\nconst CAPPED_FROM = \"Google Ads impression share: lost more searches to budget than to rank\";\n\nexport function compactBudgets(data: AdPerformanceBudgetsData): {\n month: string;\n asOf: string;\n daysLeft: number;\n rows: Array<Record<string, unknown>>;\n} {\n const labels = new Map(data.rows.map((row) => [row.key, row.label]));\n return {\n month: data.month,\n asOf: data.asOf,\n daysLeft: data.daysLeft,\n rows: data.rows.map((row) => ({\n ...roundDeep({\n headline: budgetHeadline(row, data.asOf),\n label: row.label,\n status: row.status,\n budget: row.budget.amount,\n currency: row.budget.currency,\n spent: whole(row.spent),\n plannedByNow: Math.round(row.plannedByNow),\n projected: whole(row.projected),\n ...(row.runsOutOn ? { runsOutOn: row.runsOutOn } : {}),\n remaining: whole(row.remaining),\n dailyNeeded: row.dailyNeeded,\n ...(row.partOf ? { partOf: labels.get(row.partOf) ?? row.partOf } : {}),\n ...(row.partsTotal !== null && row.partsTotal > row.budget.amount ? { partsTotal: row.partsTotal } : {}),\n ...(row.cappedCampaigns ? { cappedCampaigns: { count: row.cappedCampaigns, from: CAPPED_FROM } } : {}),\n }),\n // Amounts stay in the budget's currency; the rate into the one asked for (--currency) is kept unrounded.\n ...(row.shownIn ? { shownIn: row.shownIn } : {}),\n })),\n };\n}\n\nexport function budgetsHints(data: AdPerformanceBudgetsData): string[] {\n if (data.budgets.length === 0)\n return [\n \"No monthly budget is set, so nothing paces against a plan. Ask the person what they plan to spend a month, then: baker ads performance budgets set --amount <n> --currency <ISO>.\",\n ];\n const hints = [\n \"Tell the person each headline as it is. Budgets are independent: a budget inside another (partOf) is paced on its own, and is shown nested only for reading.\",\n ];\n for (const row of data.rows)\n if (row.partsTotal !== null && row.partsTotal > row.budget.amount)\n hints.push(\n `The budgets inside ${row.label} add up to more than ${row.label} itself: ask which number is the real plan before judging the pace.`,\n );\n if (data.rows.some((row) => (row.cappedCampaigns ?? 0) > 0))\n hints.push(\n \"cappedCampaigns: Search campaigns whose daily budget ran out on some days this month. Name them with baker ads performance impression-share; next to will_underspend it means the monthly plan has room and those daily budgets are low.\",\n );\n return hints;\n}\n\n// --- flags → requests ---\n// Null clears, so it is sent only with --clear: a missing amount, target or segment is left out for the schema to refuse.\n\nconst text = (raw: unknown) => (typeof raw === \"string\" && raw.trim() !== \"\" ? raw.trim() : undefined);\n\nfunction choiceOf(args: Args): Record<string, unknown> | undefined {\n const key = text(args.campaign) ?? text(args.term);\n if (!key || text(args.target)) return undefined;\n return {\n kind: text(args.campaign) ? \"campaign\" : \"term\",\n adAccountId: text(args.account) ?? \"\",\n key,\n ...(text(args.label) ? { label: text(args.label) } : {}),\n segment: args.clear === true ? null : enumValue(args.segment),\n };\n}\n\nfunction targetOf(args: Args): Record<string, unknown> | undefined {\n const segment = text(args.target);\n if (!segment) return undefined;\n const roas = optionalNumber(args.roas);\n return {\n segment: enumValue(segment) ?? segment,\n metric: roas !== undefined ? \"roas\" : \"cost_per_result\",\n value: args.clear === true ? null : (roas ?? optionalNumber(args.cost)),\n ...(text(args.currency) ? { currency: text(args.currency) } : {}),\n };\n}\n\nexport function segmentsSetInput(args: Args, chatId: string): Record<string, unknown> {\n const choice = choiceOf(args);\n const target = targetOf(args);\n return {\n chatId,\n ...(args.brand !== undefined ? { brandNames: commaList(args.brand) ?? [] } : {}),\n ...(args.competitors !== undefined ? { competitorNames: commaList(args.competitors) ?? [] } : {}),\n ...(choice ? { choice } : {}),\n ...(target ? { target } : {}),\n };\n}\n\nexport function budgetSetInput(args: Args, chatId: string): Record<string, unknown> {\n const platform = text(args.platform);\n return {\n chatId,\n ...(platform ? { platform: enumValue(platform) ?? platform } : {}),\n ...(text(args.account) ? { adAccountId: text(args.account) } : {}),\n segment: enumValue(args.segment) ?? \"all\",\n amount: args.clear === true ? null : optionalNumber(args.amount),\n ...(text(args.currency) ? { currency: text(args.currency) } : {}),\n };\n}\n\n// --- commands ---\n\n/** The Google Search reads read Google Ads whatever is asked, so they take no --platforms: an ignored flag is refused as unknown. */\nconst { platforms: _platforms, ...GOOGLE_SCOPE_ARGS } = SCOPE_ARGS;\n\nconst MONTHS_ARG = {\n months: {\n type: \"string\",\n description: \"Months of history for the trend, ending this month (default 6)\",\n required: false,\n },\n} as const;\n\nconst brandSplitCommand = report<typeof adPerformanceBrandSplitRequestSchema, AdPerformanceBrandSplitData>({\n name: \"brand-split\",\n schemaName: \"brandSplit\",\n schemaDescription: `Google Search split into brand (searches for the company or its products), competitor and non-brand, each with spend, its share, results, cost per result, click rate, cost per click, conversion rate and impression share, against the settled days before, and against its own target (segments set --target). Never blend brand and non-brand: brand converts cheaply because people already chose the company. Also: the month-by-month trend per segment, brand searches bought by non-brand campaigns (leakage), and terms Baker was unsure of. Segments are read by Baker from the brand and competitor names (segments) and per campaign from what its keywords spent on; other = not Search (Performance Max, Shopping, Video, Demand Gen). ${STORE_NOTE}`,\n help: \"Brand against non-brand Google Search. Example: baker ads performance brand-split --days 30\",\n path: \"brand-split\",\n args: { ...GOOGLE_SCOPE_ARGS, ...MONTHS_ARG },\n request: adPerformanceBrandSplitRequestSchema,\n input: (args) => ({ ...scopeInput(args), months: optionalNumber(args.months) }),\n compact: compactBrandSplit,\n hints: brandSplitHints,\n});\n\nconst impressionShareCommand = report<\n typeof adPerformanceImpressionShareRequestSchema,\n AdPerformanceImpressionShareData\n>({\n name: \"impression-share\",\n schemaName: \"impressionShare\",\n schemaDescription: `Per Google Search campaign: the share of the searches it could have shown on (impressionShare), the share lost to budget and to ad rank, and how often its ads showed above the organic results and first of all — now, and the change in points against the settled days before. limitedBy names the reason that dominates: budget (more budget buys the missed searches) or rank (bids, ad relevance and landing pages do). Impression share is a goal only for campaigns bidding for it (sharePrimary). ${STORE_NOTE}`,\n help: \"Where Search ads show and why they miss searches. Example: baker ads performance impression-share --days 30\",\n path: \"impression-share\",\n args: {\n ...GOOGLE_SCOPE_ARGS,\n limit: { type: \"string\", description: \"Campaigns to return (default 50)\", required: false },\n },\n request: adPerformanceImpressionShareRequestSchema,\n input: (args) => ({ ...scopeInput(args), limit: optionalNumber(args.limit) }),\n compact: compactImpressionShare,\n hints: impressionShareHints,\n});\n\nconst keywordQualityCommand = report<typeof adPerformanceKeywordQualityRequestSchema, AdPerformanceKeywordQualityData>({\n name: \"keyword-quality\",\n schemaName: \"keywordQuality\",\n schemaDescription: `Google Search keywords with their quality score (1–10) and its three parts as Google rates them — expected click rate, ad relevance, landing page experience — with spend, clicks and results, and the page each sends people to (bakerPage: a Baker landing the agent can improve). Keywords come highest spend first, as many as --limit asks (default 100). The summary weighs the score by spend and counts spend on weak parts, over the keywords returned; landings lists pages by spend on below-average landing experience. ${STORE_NOTE}`,\n help: \"Keyword quality and the pages they lead to. Example: baker ads performance keyword-quality --max-quality-score 5\",\n path: \"keyword-quality\",\n args: {\n ...GOOGLE_SCOPE_ARGS,\n \"max-quality-score\": {\n type: \"string\",\n description: \"Only keywords scored at or under this (1–10)\",\n required: false,\n },\n limit: { type: \"string\", description: \"Keywords to return (default 100)\", required: false },\n },\n request: adPerformanceKeywordQualityRequestSchema,\n input: (args) => ({\n ...scopeInput(args),\n maxQualityScore: optionalNumber(args[\"max-quality-score\"]),\n limit: optionalNumber(args.limit),\n }),\n compact: compactKeywordQuality,\n hints: keywordQualityHints,\n});\n\nconst googleReportCommand = report<typeof adPerformanceGoogleReportRequestSchema, AdPerformanceGoogleReportData>({\n name: \"google-report\",\n schemaName: \"googleReport\",\n schemaDescription: `Every section of a Google Ads review in one read, for writing a weekly or monthly report: the snapshot against the settled days before, monthly budgets and pacing, brand against non-brand (with leakage), spend by campaign type month by month, every campaign with its change (and the ones that stopped), impression share, the ad groups and keywords that brought most results, keyword quality, and what needs attention. Each section is what its own command answers. ${STORE_NOTE}`,\n help: \"A whole Google Ads review in one read. Example: baker ads performance google-report --days 7\",\n path: \"google-report\",\n args: { ...GOOGLE_SCOPE_ARGS, ...MONTHS_ARG },\n request: adPerformanceGoogleReportRequestSchema,\n input: (args) => ({ ...scopeInput(args), months: optionalNumber(args.months) }),\n compact: compactGoogleReport,\n hints: googleReportHints,\n});\n\n/** The budgets read takes what pacing takes: a month, the accounts, and the currency to show amounts in. */\nexport const BUDGETS_ARGS = PACING_ARGS;\nexport const budgetsInput = pacingInput;\n\nconst budgetsShowCommand = report<typeof adPerformanceBudgetsRequestSchema, AdPerformanceBudgetsData>({\n name: \"budgets\",\n schemaName: \"budgets\",\n schemaDescription: `The company's monthly ad budgets and how this month paces against each, each led by a headline to tell the person as is. status is one rule, the same the dashboard shows: over_budget, will_run_out (runsOutOn: the day the money ends at the last 7 days' pace), will_underspend (the month ends more than 5% short), on_track. The numbers behind it, in the budget's currency: spent so far, plannedByNow (the budget spread evenly over the month up to today), projected (where the last 7 days' pace ends the month), what is left and what each day left can spend. A budget covers one ad account or every one, all its spend or one Google Search segment (brand, competitor, non_brand); partOf names the wider budget it sits in (budgets stay independent). cappedCampaigns: Search campaigns whose daily budget ran out on some days, counted under the narrowest budget. ${STORE_NOTE}`,\n help: \"Monthly budgets and pacing. Example: baker ads performance budgets\",\n path: \"budgets\",\n args: BUDGETS_ARGS,\n request: adPerformanceBudgetsRequestSchema,\n input: budgetsInput,\n compact: compactBudgets,\n hints: budgetsHints,\n});\n\nconst budgetsSetCommand = writeCommand({\n name: \"set\",\n schemaName: \"budgets.set\",\n schemaDescription:\n \"Stage a monthly ad budget on this chat; it applies when the person publishes the chat. Every account (no --platform/--account) or one ad account (--platform --account), all its spend (default) or one Google Search segment (--segment brand|competitor|non_brand). --amount with --currency (one of the accounts' currencies); --clear removes it. A budget a person changed meanwhile stays as they set it. Ask the person: a budget is their plan, not a guess.\",\n help: \"Stage a monthly budget.\\n\\nExamples:\\n baker ads performance budgets set --amount 45000 --currency USD\\n baker ads performance budgets set --platform google --account 123 --segment brand --amount 30000 --currency USD\\n baker ads performance budgets set --platform google --account 123 --segment brand --clear\",\n path: \"/api/ads/performance/budgets/set\",\n args: {\n platform: {\n type: \"string\",\n description: \"meta | google | linkedin | x | chatgpt (omit for every account)\",\n required: false,\n },\n account: { type: \"string\", description: \"The ad account id (with --platform)\", required: false },\n segment: {\n type: \"string\",\n description: \"all (default), brand, competitor or non_brand (Google Search)\",\n required: false,\n },\n amount: { type: \"string\", description: \"What the month may spend\", required: false },\n currency: { type: \"string\", description: \"The amount's currency, e.g. EUR\", required: false },\n clear: { type: \"boolean\", description: \"Remove the budget\", required: false },\n },\n request: adPerformanceBudgetsSetRequestSchema,\n input: budgetSetInput,\n exclusive: [[[\"clear\"], [\"amount\"]]],\n});\n\nconst segmentsShowCommand = report<typeof adPerformanceSegmentsRequestSchema, AdPerformanceSegmentsData>({\n name: \"segments\",\n schemaName: \"segments\",\n schemaDescription:\n \"What decides brand, competitor and non-brand Google searches: the company's own names (its name and website unless set), its competitors' names (plus the brands it follows in the Ads library), a person's choices for single campaigns and search terms (they always win over Baker's reading), and each segment's target.\",\n help: \"What decides brand and competitor searches. Example: baker ads performance segments\",\n path: \"segments\",\n args: { full: SCOPE_ARGS.full },\n request: adPerformanceSegmentsRequestSchema,\n input: () => ({}),\n compact: (data) => roundDeep(data),\n});\n\nconst segmentsSetCommand = writeCommand({\n name: \"set\",\n schemaName: \"segments.set\",\n schemaDescription:\n \"Stage on this chat what decides brand and non-brand; applies when the person publishes it, then every search term and campaign is sorted again. --brand replaces the company's own names (company, website, product names; comma list); --competitors replaces competitor names. --campaign <id> --account <id> --segment brand|competitor|non_brand|other (other leaves it out of the split), or --term \\\"<search term>\\\" --segment brand|competitor|non_brand, sets a person's choice that wins over Baker's reading; --clear removes the choice. --target brand|competitor|non_brand with --cost <amount> --currency <ISO> or --roas <ratio> sets that segment's own target (--clear removes it). Ask the person before changing names or targets.\",\n help: 'Stage brand names, a segment choice or a segment target.\\n\\nExamples:\\n baker ads performance segments set --brand \"Parcelo, parcelo.com, Parcelo Engage\" --competitors \"Shipmora, Envialo\"\\n baker ads performance segments set --campaign 987 --account 123 --segment brand\\n baker ads performance segments set --term \"parcelo envios\" --segment brand\\n baker ads performance segments set --target non_brand --cost 40 --currency EUR',\n path: \"/api/ads/performance/segments/set\",\n args: {\n brand: {\n type: \"string\",\n description: \"Comma list: the company's own names, website and products\",\n required: false,\n },\n competitors: { type: \"string\", description: \"Comma list: competitor companies and products\", required: false },\n campaign: { type: \"string\", description: \"A Google campaign id (with --account and --segment)\", required: false },\n account: { type: \"string\", description: \"The campaign's Google Ads account id\", required: false },\n term: { type: \"string\", description: \"A search term or keyword text (with --segment)\", required: false },\n label: { type: \"string\", description: \"How the review names it (default the term or id)\", required: false },\n segment: {\n type: \"string\",\n description: \"brand, competitor, non_brand, or other (campaigns only)\",\n required: false,\n },\n target: {\n type: \"string\",\n description: \"brand, competitor or non_brand: set that segment's target\",\n required: false,\n },\n cost: { type: \"string\", description: \"Target cost per result (with --target and --currency)\", required: false },\n roas: { type: \"string\", description: \"Target return on ad spend as a ratio (with --target)\", required: false },\n currency: { type: \"string\", description: \"The target's currency, e.g. EUR\", required: false },\n clear: { type: \"boolean\", description: \"Remove the choice or the target\", required: false },\n },\n request: adPerformanceSegmentsSetRequestSchema,\n input: segmentsSetInput,\n exclusive: [\n [[\"campaign\"], [\"term\"]],\n [[\"campaign\", \"term\"], [\"target\"]],\n [[\"clear\"], [\"segment\"]],\n [[\"clear\"], [\"cost\"], [\"roas\"]],\n ],\n});\n\nexport const searchCommands = {\n \"brand-split\": brandSplitCommand,\n \"impression-share\": impressionShareCommand,\n \"keyword-quality\": keywordQualityCommand,\n \"google-report\": googleReportCommand,\n budgets: withWrites(budgetsShowCommand, { set: budgetsSetCommand }),\n segments: withWrites(segmentsShowCommand, { set: segmentsSetCommand }),\n};\n","/**\n * `baker ads performance setup` — whether the ads are set up to be read: one\n * sentence, what to fix in order, and the accounts with a problem\n * (`convex/adPerformance/setupReport.ts`). Read-only.\n */\n\nimport { type AdPerformanceSetupData, adPerformanceSetupRequestSchema } from \"@baker/api/ads-performance\";\nimport { commaList, enumValue, SCOPE_ARGS } from \"./args.ts\";\nimport { report } from \"./reportCommand.ts\";\n\ntype Account = AdPerformanceSetupData[\"accounts\"][number];\nconst CHECKS = [\"connected\", \"synced\", \"conversions\"] as const;\n\nfunction problemsOf(account: Account): Record<string, string> {\n return Object.fromEntries(\n CHECKS.flatMap((check) => (account[check].state === \"problem\" ? [[check, account[check].label]] : [])),\n );\n}\n\nexport function compactSetup(data: AdPerformanceSetupData): Record<string, unknown> {\n const problems = data.accounts.filter((account) => Object.keys(problemsOf(account)).length > 0);\n const waiting = data.accounts.filter(\n (account) => !problems.includes(account) && CHECKS.some((check) => account[check].state === \"waiting\"),\n );\n return {\n headline: data.headline,\n toFix: data.toFix,\n ...(problems.length > 0\n ? {\n problems: problems.map((account) => ({\n account: account.name,\n platform: account.platform,\n ...problemsOf(account),\n })),\n }\n : {}),\n ...(waiting.length > 0\n ? {\n waiting: waiting.map((account) => ({\n account: account.name,\n platform: account.platform,\n ...Object.fromEntries(\n CHECKS.flatMap((check) => (account[check].state === \"waiting\" ? [[check, account[check].label]] : [])),\n ),\n })),\n }\n : {}),\n fine: data.accounts.length - problems.length - waiting.length,\n ...(data.tracking.length > 0 ? { tracking: data.tracking } : {}),\n };\n}\n\nexport function setupHints(data: AdPerformanceSetupData): string[] {\n const hints = [\"Tell the person the headline as it is, then the fixes in the order of toFix.\"];\n if (data.toFix.some((entry) => entry.fix.startsWith(\"Reconnect\")))\n hints.push(\n \"A reconnection is a person's to do in Brain → Integrations: you cannot do it. Say which platform and what stops until they do.\",\n );\n if (data.toFix.some((entry) => entry.fix.includes(\"Goals\")))\n hints.push(\n \"For an account with no conversions, read what it optimises for with baker ads performance targets, then stage what counts as a result with baker ads performance goals set.\",\n );\n return hints;\n}\n\nexport const setupCommand = report<typeof adPerformanceSetupRequestSchema, AdPerformanceSetupData>({\n name: \"setup\",\n schemaName: \"setup\",\n schemaDescription: `Whether the ads are set up to be read, in one headline: per ad account connected, numbers synced and conversions counted over 30 days; per platform whether visits from its ads name their ad. toFix lists what a person has to do, in order, with the fix; problems names the accounts with one; fine counts the rest. The same checks as Measure → Ads → Setup. Reads Baker's stored copy of every connected ad platform (no platform call). --full returns every account, the fine ones included.`,\n help: \"Is everything set up? Example: baker ads performance setup\",\n path: \"setup\",\n args: { platforms: SCOPE_ARGS.platforms, \"ad-account-ids\": SCOPE_ARGS[\"ad-account-ids\"], full: SCOPE_ARGS.full },\n request: adPerformanceSetupRequestSchema,\n input: (args) => ({\n platforms: commaList(args.platforms)?.map((item) => enumValue(item) ?? item),\n adAccountIds: commaList(args[\"ad-account-ids\"]),\n }),\n compact: compactSetup,\n hints: setupHints,\n});\n","/**\n * `baker ads performance trend` — the numbers over time, split one way: the\n * read behind the dashboard's charts (`convex/adPerformance/reports.ts`\n * `trend`), with the same grains, splits and scope. Read-only.\n */\n\nimport {\n AD_TREND_GRANULARITIES,\n AD_TREND_GROUPS,\n type AdPerformanceTrendData,\n type AdTrendSeriesPoint,\n adPerformanceTrendRequestSchema,\n} from \"@baker/api/ads-performance\";\nimport { enumValue, optionalNumber, SCOPE_ARGS, scopeInput } from \"./args.ts\";\nimport { roundNumber } from \"./report.ts\";\nimport { report, STORE_NOTE } from \"./reportCommand.ts\";\n\nexport const TREND_ARGS = {\n ...SCOPE_ARGS,\n grain: {\n type: \"string\",\n description: `${AD_TREND_GRANULARITIES.join(\", \")} (default day; week starts Monday; total is one bucket over the window)`,\n required: false,\n },\n \"group-by\": {\n type: \"string\",\n description: `${AD_TREND_GROUPS.join(\", \")} (default platform). kind: the campaign's type; segment: Google Search brand segment`,\n required: false,\n },\n limit: {\n type: \"string\",\n description:\n \"With --group-by campaign: campaigns kept on their own by spend, 1-50 (default 10); the rest sum into __other\",\n required: false,\n },\n} as const;\n\nexport function trendInput(args: Record<string, unknown>) {\n return {\n ...scopeInput(args),\n granularity: enumValue(args.grain),\n groupBy: enumValue(args[\"group-by\"]),\n limit: optionalNumber(args.limit),\n };\n}\n\nconst nullableRound = (value: number | null) => (value === null ? null : roundNumber(value));\n\nfunction compactPoint(point: AdTrendSeriesPoint, groupBy: AdPerformanceTrendData[\"groupBy\"]): Record<string, unknown> {\n const { metrics, ratios } = point;\n return {\n bucket: point.bucket,\n ...(groupBy === \"platform\" || groupBy === \"none\" ? {} : { group: point.groupKey }),\n ...(point.platform === \"all\" ? {} : { platform: point.platform }),\n currency: point.currency,\n spend: roundNumber(metrics.spend),\n impressions: roundNumber(metrics.impressions),\n clicks: roundNumber(metrics.clicks),\n results: roundNumber(metrics.results),\n ...(metrics.resultValue > 0\n ? { resultValue: roundNumber(metrics.resultValue), roas: nullableRound(ratios.resultValuePerSpend) }\n : {}),\n costPerResult: nullableRound(ratios.costPerResult),\n ctr: nullableRound(ratios.ctr),\n ...(point.mature ? {} : { mature: false }),\n };\n}\n\nexport function compactTrend(data: AdPerformanceTrendData): Record<string, unknown> {\n return {\n window: data.window,\n granularity: data.granularity,\n groupBy: data.groupBy,\n rows: data.points.map((point) => compactPoint(point, data.groupBy)),\n matureThrough: data.matureThrough.map((entry) => ({ platform: entry.platform, date: entry.date })),\n };\n}\n\n/** The grain the dashboard's chart picks for a window this long (`granularityOf`): day to ~2 months, week to ~6½. */\nfunction chartGrain(days: number): \"day\" | \"week\" | \"month\" {\n return days <= 62 ? \"day\" : days <= 200 ? \"week\" : \"month\";\n}\n\nconst FINER = { day: 0, week: 1, month: 2, total: 3 } as const;\n\nexport function trendHints(\n data: AdPerformanceTrendData,\n request: { groupBy: AdPerformanceTrendData[\"groupBy\"] } = { groupBy: data.groupBy },\n args: Record<string, unknown> = {},\n): string[] {\n const hints: string[] = [];\n if (request.groupBy !== \"campaign\" && args.limit !== undefined)\n hints.push(\n `--limit only applies with --group-by campaign (the campaigns kept on their own); with --group-by ${request.groupBy} every row is returned.`,\n );\n const suggested = chartGrain(data.window.days);\n if (FINER[data.granularity] < FINER[suggested])\n hints.push(\n `${data.points.length} rows at the ${data.granularity} grain over ${data.window.days} days: --grain ${suggested} reads it as the dashboard's chart does, and shows the shape without the daily noise.`,\n );\n if (data.points.some((point) => !point.mature))\n hints.push(\n \"Rows with mature: false include days whose results are still settling (each platform's matureThrough), so their cost per result reads high: compare only settled rows.\",\n );\n if (data.points.some((point) => point.groupKey === \"__other\"))\n hints.push(\n \"__other sums every campaign past the top --limit by spend (max 50). Campaign names: baker ads performance entities --campaign-ids <ids>.\",\n );\n const currencies = new Set(data.points.map((point) => point.currency));\n if (currencies.size > 1)\n hints.push(\n `Amounts are in ${currencies.size} currencies (${[...currencies].join(\", \")}): never add them; --currency <ISO> converts every one.`,\n );\n if (data.points.length === 0) hints.push(\"Nothing delivered in this window and scope.\");\n return hints;\n}\n\nexport const trendCommand = report<typeof adPerformanceTrendRequestSchema, AdPerformanceTrendData>({\n name: \"trend\",\n schemaName: \"trend\",\n schemaDescription: `The numbers over time, split one way — what the dashboard's charts draw. One row per bucket (--grain day | week | month | total) and group (--group-by platform | ad_account | campaign | kind | segment | none): spend, impressions, clicks, results, cost per result, CTR, and result value with ROAS where results carry value. mature: false marks a bucket whose last day has not settled yet. --group-by campaign keeps the top --limit campaigns by spend and sums the rest into __other. Ids only: names come from accounts or entities. Default the last 30 complete days, by day, per platform. ${STORE_NOTE}`,\n help: \"Spend and results over time, split one way. Example: baker ads performance trend --days 90 --grain week --group-by campaign\",\n path: \"trend\",\n args: TREND_ARGS,\n request: adPerformanceTrendRequestSchema,\n input: trendInput,\n compact: compactTrend,\n hints: trendHints,\n});\n"],"mappings":"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","names":["z","z","z","z","z","idList","z","whole","text","moved","field","z","z","PLATFORMS","z","PLATFORMS","z","idList","z","z","idList","z","z","z","z","z","z","z","idList","z","z","z","z","z","z","idList","z","z","defineCommand","z","defineCommand","written","defineCommand","share","share","defineCommand","defineCommand","defineCommand","defineCommand","defineCommand","share","defineCommand","defineCommand","nullableRound","defineCommand","defineCommand","defineCommand","defineCommand","defineCommand","nullableRound","compactRow","round","money","text","_platforms","nullableRound","z","defineCommand"]}
|