Rules Schema

Status boundary:§1 记录 2026-06 Task V2 rules inventory;§2–§5 是历史 proposal。当前 selected Target 由 Task V3 Product / Domain Contract 定义,实施与环境状态见 Task V3 Rollout 状态快照。V2/V2+ 内容保留为 point-in-time compatibility context。

2026-06 snapshot sources(当时 verified 2026-06-01):

  • callytics-common/src/utils/due-at.ts — SLA / priority windows / business hours / timezone
  • callytics-common/src/db/schema/task-ui.ts — backlog days / AI assignable categories
  • callytics-common/src/db/schema/store-config.ts — store_config 表(pricing JSONB / leadEmails)
  • callytics-common/src/db/schema/operating-schedules.ts + operating-overrides.ts + blackout-periods.ts — 营业时间 / 单日覆盖 / SLA 黑名单时段
  • callytics-infrastructure/lambda/contacts-analyzer/src/core/prompt-builder.ts — attempt threshold(prompt 内硬编码)
  • studio-website-monorepo/apps/api/src/routes/tasks/list.ts — due_soon 24h(SQL 硬编码) Historical Task V2+ audit: 工程审计与设计建议 Task V3 selected Target: Task V3 Product / Domain Contract Current rollout evidence boundary: Task V3 Rollout 状态快照 Historical proposal: ../tasks-feature/design/task-pipeline-deliverable-codex.md §6 + §7 + §14 阅读顺序: Task V3 contract / rollout statusTask V2 inventory (§1) → historical proposal (§2–§5)。

0. Rules 到底是什么(读之前必看)

Rules 不是一张 DB 表。它是 6 类物理位置的混合体,共同决定 Tasks / Lead Tracker / Dashboard / AI prompt 的行为。

物理位置内容谁读谁能改
Code constant (TS export)SLA / priority windows / business hours / backlog days / AI assignable categorieslead-tracking Lambda / contacts-analyzer Lambda / studio-api改 code + redeploy
Prompt text (硬编码)Attempt threshold = 3contacts-analyzer prompt改 prompt-builder.ts + redeploy
Route SQL (硬编码)due_soon = 24hstudio-api tasks/list.ts改路由代码 + redeploy
DB 表 store_config (JSONB)pricing / leadEmails / alias / activatedAtstudio-api 读UI PATCH /v3/setup/stores/:id
DB 表 operating_schedules + operating_overrides + blackout_periods营业时间 / 单日覆盖 / SLA 黑名单时段studio-api / SLA 计算UI
2026-06 legacy proposalallowedTypeCategories / allowedProgressTypes / allowedCloseResults旧 Task Orchestrator/prompt contractHistorical;不得作为 Target allowed set
设计常量(代码未实现)Revenue Benchmarks($149 / 0.60 / 0.70 / 0.75 等)(无,目前 Dashboard 的 Impacted Revenue 不按此算)n/a
法律硬约束Quiet Hours 9PM-8AM(TCPA),不可关闭所有 outbound contact 模块不可改(法律)

Target Task 状态:Task-specific rules 不再由 global typeCategory / progressType / closeResult 三组 allowed set 定义,而由 versioned Task Policy Catalog 驱动 prompt/tool schema、backend validation、UI options 与 reporting。下文 storePolicystore_config.rules 是历史 proposal,不能直接实施。


1. Current Schema(2026-06-01 live)

1.1 Lead First Response — Lead Outreach SLA

来源: callytics-common/src/utils/due-at.ts:27。Lead Outreach task dueAt = createdAt + SLA,倒计时只在营业时段内走。

配置项默认值物理位置Nullable影响
DEFAULT_SLA_MINUTES5 minTS const (due-at.ts:27)NOT NULL(const)Lead Outreach task dueAt = createdAt + 5min
Due Soon(Lead)2 min(documented,代码未实现)"即将到期"红卡片提前量;代码里没有此变量,UI 静态文字

⚠️ 可配置范围(SLA 1-30 min / Due Soon 1-5 min)是 v1 设计意图,代码里没有 store-level override 通道。所有 store 共用 DEFAULT_SLA_MINUTES = 5

1.2 Task Deadline by Priority — Follow-up 截止窗口

来源: callytics-common/src/utils/due-at.ts:20-24 PRIORITY_WINDOW_MINUTES

配置项默认值物理位置Nullable影响
PRIORITY_WINDOW_MINUTES.high4h (240 min)TS constNOT NULLhigh task dueAt = createdAt + 4h
PRIORITY_WINDOW_MINUTES.medium24h (1440 min)TS constNOT NULLmedium task dueAt = createdAt + 24h
PRIORITY_WINDOW_MINUTES.low72h (4320 min)TS constNOT NULLlow task dueAt = createdAt + 72h
Task Due Soon1h(documented)/ 24h(代码真实值)TS const(documented)/ SQL string(real)Follow-up "即将到期"判定;Rules UI 写 1h,但路由 SQL 写死 24h(apps/api/src/routes/tasks/list.ts:101),两者未接通

⚠️ Task Due Soon 漂移: studio-api/.../tasks/list.ts:95-103 注释直接写 (24h threshold),SQL 是 t.due_at BETWEEN NOW() AND NOW() + INTERVAL '24 hours',不读任何 store config。Rules UI 文档里写 1h 是设计意图,代码现状是 24h。

1.3 Business Hours — 营业时段(SLA 窗口推迟基准)

来源: callytics-common/src/utils/due-at.ts:30-36 默认值 + DB 表 store-level 覆盖。

配置项默认值(code const)物理位置Nullable影响
DEFAULT_BUSINESS_HOURS.openHour8 (8 AM local)TS constNOT NULL落在 openHour 之前的 dueAt 推到当天 openHour
DEFAULT_BUSINESS_HOURS.closeHour21 (9 PM local)TS constNOT NULL落在 closeHour 之后的 dueAt 推到次日 openHour
DEFAULT_TIMEZONEAmerica/New_YorkTS constNOT NULLdueAt 推算的时区基准
operating_schedules.scheduleper-day open/close JSONBDB tableNOT NULLstore-level 营业时间模板,有 effective_date 历史
operating_overrides.overrideData{isClosed: true}{openTime, closeTime} JSONBDB tableNOT NULL单日覆盖(节假日 / 临时停业)
blackout_periods(start_time, end_time, recurrence?)DB tableNOT NULLSLA 暂停区间(婚礼 / 设备维护等)

store-level operating_schedules / overrides / blackouts 是 DB-stored,跟 due-at.ts 的 hardcoded default 是两套并行机制。SLA 计算何时读哪个仍在演进。

1.4 Revenue Benchmarks — 营收归因基准(设计常量,代码未实现)

来源: v1 设计文档。callytics-common / callytics-infrastructure / studio-website-monorepo 全仓搜不到 $149 / 0.60 / 0.70 / 0.75 常量。Dashboard 的 Impacted Revenue 目前不按此算。

配置项默认值(设计)物理位置Nullable影响
Customer Avg Price$149 / mo(无,未接线)多种 closeResult 共用基准
Promotion Avg Price$129 / mo(无)推广客单价
Upgrade Avg Incremental$40 / mo(无)升级增量单价
Event Registration Fee$30 一次性(无)活动报名费
Complaint Retention Window90 天(无)投诉解决后客户须 90 天内未流失才计归因
Complaint Attribution Coefficient0.60(无)投诉挽留归因系数
Freeze Recovery Coefficient0.70(无)冻结恢复归因系数
Payment Recovery Coefficient0.75(无)支付恢复归因系数

这一节记录的是目标设计,实施前需先决定:落 code const 还是落 store_config.pricing JSONB(已有字段,目前空对象)。

1.5 Lead Thresholds — Attempt 边界

来源: callytics-infrastructure/lambda/contacts-analyzer/src/core/prompt-builder.ts:331 的 prompt 文本。

配置项默认值物理位置Nullable影响
Attempt Threshold3Prompt 文本里硬编码NOT NULLAI 判 unreachable(≥3 次未接通,客户问题)vs neglected(<3 次,员工失职)

⚠️ Prompt 内硬编码,Rules UI 不可调: prompt 文本里明写 Lead attempt threshold = 3 contact attempts (Phase 2 lost_contact, Phase 3 unreachable/neglected boundary)。修改它必须改 prompt-builder.ts + redeploy,UI 上 Rules 页改 Attempt Threshold 数字不会影响 AI 判定。

1.6 Backlog 视窗 — 多少天没动算 backlog

来源: callytics-common/src/db/schema/task-ui.ts:94-96

配置项默认值物理位置Nullable影响
LEAD_CATEGORIES['lead_outreach', 'lead_follow_up']TS constNOT NULL哪些 typeCategory 走更严的 backlog 时限
LEAD_BACKLOG_DAYS7TS constNOT NULLLead 类 task 7 天没动算 backlog
DEFAULT_BACKLOG_DAYS14TS constNOT NULL其他类 task 14 天没动算 backlog

studio-api/.../tasks/list.ts:120-121, 135-136 直接 inline 这两个常量进 SQL。

1.7 AI Assignable Categories — AI 能创建哪些 typeCategory

来源: callytics-common/src/db/schema/task-ui.ts:105

配置项默认值物理位置Nullable影响
AI_ASSIGNABLE_CATEGORIES9 个 typeCategory 去掉 lead_outreach = 8 个TS constNOT NULLContact Analyzer AI 创建 task 时只能选这 8 个;员工手动可选全 9 个

不是 AI 能力限制,是入口分工: lead_outreach 标签意思就是"新 lead 第一次联系",只能由 lead-tracking 入口创建。

1.8 store_config 表 — DB-stored store-level 配置(非 rules 但相关)

来源: callytics-common/src/db/schema/store-config.ts这是当前唯一的 store-level 配置 DB 表,但目前不存 SLA / threshold / benchmark。

FieldTypeNullableDefault用途
storeId (PK, FK→rc_stores)uuidNOT NULLstore 标识
aliastextNULLNULL用户设的展示名(NULL 用 RC 同步来的 name)
activatedAttimestamptzNULLNULL首次激活进 active workspace 时间(NULL = 未激活)
leadEmailstext[]NULL[]store-level lead 邮件通知列表(DB nullable,但代码用 .default([]) 兜底)
pricingjsonbNULL{}定价配置(intro offers / class packs / membership tiers)— 目前 shape 未文档化(DB nullable,代码用 .default({}) 兜底)
updatedAttimestamptzNOT NULLNOW()系统时间戳

pricing JSONB 已有字段,但 Revenue Benchmarks 没接进来。Final 可能扩展此 JSONB 而不新建 rules 表。

1.9 Quiet Hours — 法律硬约束

不在代码 const 也不在 DB,是产品规则。

项目可配置
夜间静默时段9 PM – 8 AM(客户本地时区)否(TCPA 47 U.S.C. § 227(b)(1))
Custom Restrictions店铺可加严不可放宽UI(目前未接 DB)

落入静默时段的 dueAt 自动推到下一个可联系时刻。注意: DEFAULT_BUSINESS_HOURS 是 8 AM–9 PM(due-at.ts:30-33),刚好是 Quiet Hours 的补集,但语义不同: business hours 是"营业时段"(SLA 推迟基准),Quiet Hours 是"法律不可拨打时段"。代码里只实现了前者。


2. Historical proposed schema(不是 Target)

设计原则: rules 仍主要是 code constant + prompt input,不强制落新表。Task Orchestrator 把 6 类来源拼成 storePolicy 注入 prompt。需要 store-level override 的 config(SLA / Attempt Threshold / Revenue Benchmark)扩展 store_config JSONB,不新建 rules 表。

2.1 Lead First Response — Lead Outreach SLA

配置项目标默认值物理位置变化
DEFAULT_SLA_MINUTES5 minTS const + 可被 store_config.rules.leadSlaMinutes 覆盖增加 store-level override 通道
Lead Due Soon2 minTS const + override同上

2.2 Task Deadline by Priority

配置项目标默认值物理位置变化
PRIORITY_WINDOW_MINUTES.{high,medium,low}4h / 24h / 72hTS const + override同上
Task Due Soon统一为 1h(或 store override)tasks/list.ts 读 const,不再 inline 24 hours必须修 routes/tasks/list.ts: SQL 改读常量 + store config

2.3 Business Hours / Operating Schedules

无变化。继续以 operating_schedules + operating_overrides + blackout_periods DB 表为 store-level 主源,DEFAULT_BUSINESS_HOURS const 仅 fallback。

2.4 Revenue Benchmarks(目标: 接线 + 可配置)

配置项目标默认值物理位置变化
Customer Avg Price$149 / mostore_config.rules.revenueBenchmarks.customerAvgPrice必须新增字段并接线进 Dashboard Impacted Revenue 计算
Promotion Avg Price$129 / mo同上同上
Upgrade Avg Incremental$40 / mo同上同上
Event Registration Fee$30同上同上
Complaint Retention Window90 天同上同上
Complaint Attribution Coefficient0.60同上同上
Freeze Recovery Coefficient0.70同上同上
Payment Recovery Coefficient0.75同上同上

2.5 Lead Thresholds(目标: 移出 prompt 文本)

配置项目标默认值物理位置变化
Attempt Threshold3(可按 task type 配置)store_config.rules.attemptThreshold + 由 Task Orchestrator 注入 prompt 作为 storePolicy.retryThreshold必须从 prompt 文本里删硬编码 3,改由 prompt template 占位符替换

来源: codex doc §14 "lead retry threshold | 默认 3 次 meaningful attempts,但按 task type 可配置"。

2.6 AI Assignable Categories — 按 lifecycle 动态收窄(新增)

来源: codex doc §7 "typeCategory allowed set"。

Customer lifecycle / stateAI 可选 typeCategory(allowed set)物理位置
lead activelead_follow_up, booked_not_convertedCode(Task Orchestrator 按 contact.lifecycleState 算)
member activecancellation_risk, retention, upgrade, renewal, referral同上
churned re-engagementwin_back同上
terminal / DNC / wrong numbernone(只能 close 已有)同上

Static set 仍是 AI_ASSIGNABLE_CATEGORIES(8 values),dynamic set 是 static set 与 lifecycle policy 的交集。

2.7 storePolicy — Prompt input shape(新)

来源: codex doc §6 "Prompt input should include"。Task Orchestrator 把 rules 拼成 JSON 注入 prompt,prompt 不直接访问 store_config / lifecycle。

Prompt input 字段内容来源
allowedTypeCategories当前 lifecycle 算出的 typeCategory 集§2.6 + AI_ASSIGNABLE_CATEGORIES
allowedProgressTypestask_progress_events.progressType 全枚举(6 values)TASK_PROGRESS_TYPE const
allowedCloseResultstasks.closeResult final 14 valuesTASK_CLOSE_RESULT const
storePolicy.dncDNC 标记contact.doNotContact
storePolicy.leadSlaMinutes当前 SLA(default or store override)§2.1
storePolicy.retryThresholdAttempt threshold§2.5
storePolicy.quietHoursTCPA 时段 + custom restrictionshardcoded + custom restrictions DB
storePolicy.businessHours营业时段operating_schedules
storePolicy.storeGuardstoreId 隔离 tokenrequest context

2.8 store_config 表 — 扩展 JSONB(新字段)

新增 rules 列(jsonb)集中存所有可 store-level override 的 rules:

FieldTypeNullableDefault用途
rulesjsonbNOT NULL{}{ leadSlaMinutes?, taskDueSoonMinutes?, priorityWindows?: {high,medium,low}, attemptThreshold?, revenueBenchmarks?: {...}, customRestrictions?: [...] }

shape 待最终拍板;新增字段不破坏现有 pricing / leadEmails


3. Historical proposal delta(Current → 旧 proposed Final)

3.1 Added(新增字段 / 新表 / 新 const / 新 prompt input)

AddedWhereTypeReason
store_config.rulesstore_config 表新 jsonb 列jsonb DEFAULT {}集中 store-level overridable rules
TASK_PROGRESS_TYPE constTask V2 compatibility const6 valuesV3 Target 拆为 typed ActivityBusiness Progress
storePolicy prompt inputTask Orchestrator → prompt JSONobjectrules 统一注入入口
allowedTypeCategories lifecycle mapCode policy modulefunction (contact) → TypeCategory[]dynamic guardrail,§2.6
Revenue benchmark 字段接线studio-api Dashboard 计算路径code wiring + DB read当前完全未实现

3.2 Removed / Moved(从硬编码搬到 const + override)

Removed fromMoved toReason
prompt-builder.ts:331 硬编码 Lead attempt threshold = 3prompt template {{retryThreshold}} 占位 + storePolicy.retryThreshold 注入让 Rules UI 真能调
tasks/list.ts:101 硬编码 INTERVAL '24 hours'const TASK_DUE_SOON_MINUTES + store override让 Rules UI 真能调
tasks/list.ts:120-136 硬编码 LEAD_BACKLOG_DAYS / DEFAULT_BACKLOG_DAYS inline仍走 const 但允许 store override保持灵活

3.3 Modified

FieldBeforeAfterWhy
AI_ASSIGNABLE_CATEGORIES8 static values8 static + per-request dynamic filter by customer lifecyclecode guardrail 收窄;e.g. churned 只允许 win_back,DNC 不允许任何
DEFAULT_SLA_MINUTES / PRIORITY_WINDOW_MINUTESTS const 唯一来源TS const 作 fallback;store_config.rules 优先让 store override 真能用

3.4 Unchanged(明确保留)

  • DEFAULT_BUSINESS_HOURS const + operating_schedules / operating_overrides / blackout_periods 表 — 三层 fallback 链路不变
  • Quiet Hours TCPA 硬约束 — 不可配置
  • store_config 已有列(alias / activatedAt / leadEmails / pricing)— 不动
  • LEAD_CATEGORIES / LEAD_BACKLOG_DAYS / DEFAULT_BACKLOG_DAYS const 值不变,只是允许 store override

4. Legacy Prompt Output ↔ Rules 字段对照

Reviewer 用本表验证 prompt 是否正确消费 rules 并遵守 allowed set。

Prompt消费的 rules 字段验证什么
01 Triagen/a
02 Classifyn/a
03 Verifyn/a
04 Coachingn/a
05 Contact ProfilestorePolicy.retryThresholdAI 判 unreachable vs neglected 用 threshold,不再硬编码 3
06 Task DecisionallowedTypeCategories / allowedProgressTypes / allowedCloseResults / storePolicy.{dnc,leadSlaMinutes,retryThreshold,quietHours,businessHours,storeGuard}核心 reviewer 关注点:输出 typeCategory 必在 dynamic allowed set;progressType ∈ 6 values;closeResult ∈ 14 values;DNC 时不创建 outreach;低置信度走 no_op / needs_review
07 Task Playbook(read-only,不写库)推荐 close 时 suggestedCloseResult ∈ final 14 values(不推荐 deprecated 的 attempted)

5. Historical Open Product Policy

来源: historical Codex doc §14。本表不属于 V3 Target scope。

问题推荐默认影响 rules schema?
store_config.rules 是否独立表还是 JSONB?JSONB 扩展(最小破坏)决定 §2.8 物理结构
Revenue Benchmarks 真的实施还是再等?与 Dashboard Impacted Revenue 重构一起推决定 §1.4 / §2.4 优先级
Attempt Threshold per task type 配置?默认 3,允许 per typeCategory override决定 storePolicy.retryThreshold 是 number 还是 {typeCategory: number}
Custom Restrictions 落库?store_config.rules.customRestrictions array决定 UI 同步策略
Low-confidence AI proposal 阈值?confidence < 0.7 → no_op / human review影响 Task Orchestrator 行为,不动 rules schema

6. Appendix A — Re-verification commands

2026-06-01 verified。文档 stale 时(>30 天)重跑下方命令并比对。

# 1. SLA / priority windows / business hours / timezone 常量
grep -E "DEFAULT_SLA_MINUTES|PRIORITY_WINDOW_MINUTES|DEFAULT_BUSINESS_HOURS|DEFAULT_TIMEZONE" \
  ../../../../../callytics-common/src/utils/due-at.ts

# 2. Backlog 常量 + AI assignable categories
grep -E "LEAD_BACKLOG_DAYS|DEFAULT_BACKLOG_DAYS|LEAD_CATEGORIES|AI_ASSIGNABLE_CATEGORIES" \
  ../../../../../callytics-common/src/db/schema/task-ui.ts

# 3. store_config 当前字段
grep -E "^\s*[a-zA-Z]+:|pgTable" \
  ../../../../../callytics-common/src/db/schema/store-config.ts

# 4. Attempt threshold 是否仍 prompt 内硬编码
grep -n "attempt threshold" \
  ../../../../../callytics-infrastructure/lambda/contacts-analyzer/src/core/prompt-builder.ts
# 期望: line 331 + 634 仍含 "Lead attempt threshold = 3"

# 5. due_soon 是否仍 SQL 硬编码
grep -n "due_soon\|INTERVAL '24 hours'" \
  ../../../../../studio-website-monorepo/apps/api/src/routes/tasks/list.ts
# 期望: line 101 / 255 仍含 INTERVAL '24 hours'

# 6. Revenue benchmark 是否已实施
grep -rn "customerAvgPrice\|complaintRetention\|0\.60\|0\.75" \
  ../../../../../callytics-common ../../../../../studio-website-monorepo
# 期望: 无匹配(未实施)

# 7. Historical Codex proposal 对照
grep -E "allowedTypeCategories|allowedProgressTypes|allowedCloseResults|storePolicy|retryThreshold" \
  ../../tasks-feature/design/task-pipeline-deliverable-codex.md

7. Cross-References