feat(ai): F1-5b Wave A 中段 沙箱业务日全栈架构主体收口 (W1)
完成 F1-5b 任务:
- T1 RuntimeContext unit 测试基础(36 case PASS,本地不入仓走 .gitignore:71)
- A1 admin_service.py 4 处 CURRENT_DATE → business_date 改造
- _get_range_stats / _get_7d_trend / _get_app_distribution
- 上下界双全(下界 - 6 days + 上界 < + 1 day,Step 4b 暴露原 PR
上界缺失,sandbox=4-20 时 trend_7d 漏 4-21~5-01 数据 → 修补)
- 全局聚合 list_trigger_jobs / get_budget 保留 CURRENT_DATE
(Neo D 决策选 A: 多 site 时全局无单一业务日)
- A2 fdw_queries:113 / 2552 异常分支兜底 + 三层 fallback + warning
- conn=None 也尝试 get_runtime_context(自开 conn)
- RuntimeContext 不可用降级真实 today + logger.warning
- A3 _fdw_context docstring 显式登记唯一 ETL 入口架构契约
(D2 完整且统一: 所有 ETL 视图查询通过 _fdw_context 自动 SET 三个
GUC: site_id / business_date / runtime_mode)
- 防御 hook post_edit_business_date_check.py
Wave 2 后续 PR 引回 CURRENT_DATE / date.today() 即提醒
双口径验证(§3.1 4a + 4b):
- 4a live: dashboard trend_7d 2 条 4-30~5-01 (真实今天)
- 4b sandbox=2026-04-20: trend_7d 1 条仅 4-20 (业务日上界生效硬证据)
- pytest test_runtime_context 36/36 全过
未完(下一批 Wave A): T2 integration / UI-1/2/4 / MP-3/5 / MP-1 / BE-1
F1-5b-tasks.md 新增 + audit 记录已就位
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ from app.ai.budget_tracker import BudgetTracker
|
||||
from app.database import get_connection
|
||||
from app.services.runtime_context import (
|
||||
RuntimeContext,
|
||||
as_runtime_today_param,
|
||||
get_runtime_context,
|
||||
runtime_insert_columns,
|
||||
)
|
||||
@@ -94,12 +95,24 @@ class AdminAIService:
|
||||
"""指定时间段内的调用次数、成功率、Token 消耗、平均延迟。
|
||||
|
||||
字段名沿用 today_* 前缀以兼容前端 DashboardResponse schema。
|
||||
|
||||
F1-5b A1: 时间窗口基准日:
|
||||
- site_id 非 None: 用 RuntimeContext.business_date(sandbox 模式取虚拟日)
|
||||
- site_id 为 None: 全局聚合,用 PG CURRENT_DATE(全局视图无单一业务日)
|
||||
"""
|
||||
site_clause, site_params = _site_filter(site_id)
|
||||
|
||||
if date_from and date_to:
|
||||
time_clause = "created_at >= %s::date AND created_at < (%s::date + INTERVAL '1 day')"
|
||||
time_params: tuple = (date_from, date_to)
|
||||
elif site_id is not None:
|
||||
days = range_days if range_days and range_days > 0 else 1
|
||||
today = as_runtime_today_param(site_id)
|
||||
time_clause = (
|
||||
"created_at >= %s::date - (%s::int - 1) * INTERVAL '1 day' "
|
||||
"AND created_at < %s::date + INTERVAL '1 day'"
|
||||
)
|
||||
time_params = (today, days, today)
|
||||
else:
|
||||
days = range_days if range_days and range_days > 0 else 1
|
||||
time_clause = (
|
||||
@@ -142,8 +155,26 @@ class AdminAIService:
|
||||
}
|
||||
|
||||
async def _get_7d_trend(self, site_id: int | None) -> list[dict]:
|
||||
"""近 7 天按日聚合。"""
|
||||
site_clause, params = _site_filter(site_id)
|
||||
"""近 7 天按日聚合。
|
||||
|
||||
F1-5b A1: site_id 非 None 用业务日上下界(sandbox 取虚拟日);
|
||||
site_id None 全局聚合用 CURRENT_DATE。
|
||||
2026-05-05 修补:同时加上界 < %s + 1day,sandbox 不漏未来数据。
|
||||
"""
|
||||
site_clause, site_params = _site_filter(site_id)
|
||||
if site_id is not None:
|
||||
today = as_runtime_today_param(site_id)
|
||||
time_clause = (
|
||||
"created_at >= %s::date - INTERVAL '6 days' "
|
||||
"AND created_at < %s::date + INTERVAL '1 day'"
|
||||
)
|
||||
params = (today, today) + site_params
|
||||
else:
|
||||
time_clause = (
|
||||
"created_at >= CURRENT_DATE - INTERVAL '6 days' "
|
||||
"AND created_at < CURRENT_DATE + INTERVAL '1 day'"
|
||||
)
|
||||
params = site_params
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
@@ -154,7 +185,7 @@ class AdminAIService:
|
||||
COUNT(*) AS calls,
|
||||
COUNT(*) FILTER (WHERE status = 'success') AS success_count
|
||||
FROM biz.ai_run_logs
|
||||
WHERE created_at >= CURRENT_DATE - INTERVAL '6 days'
|
||||
WHERE {time_clause}
|
||||
{site_clause}
|
||||
GROUP BY day
|
||||
ORDER BY day
|
||||
@@ -176,8 +207,26 @@ class AdminAIService:
|
||||
]
|
||||
|
||||
async def _get_app_distribution(self, site_id: int | None) -> list[dict]:
|
||||
"""各 App 调用占比。"""
|
||||
site_clause, params = _site_filter(site_id)
|
||||
"""各 App 调用占比。
|
||||
|
||||
F1-5b A1: site_id 非 None 用业务日上下界(sandbox 取虚拟日);
|
||||
site_id None 全局聚合用 CURRENT_DATE。
|
||||
2026-05-05 修补:同时加上界 < %s + 1day,sandbox 不漏未来数据。
|
||||
"""
|
||||
site_clause, site_params = _site_filter(site_id)
|
||||
if site_id is not None:
|
||||
today = as_runtime_today_param(site_id)
|
||||
time_clause = (
|
||||
"created_at >= %s::date - INTERVAL '6 days' "
|
||||
"AND created_at < %s::date + INTERVAL '1 day'"
|
||||
)
|
||||
params = (today, today) + site_params
|
||||
else:
|
||||
time_clause = (
|
||||
"created_at >= CURRENT_DATE - INTERVAL '6 days' "
|
||||
"AND created_at < CURRENT_DATE + INTERVAL '1 day'"
|
||||
)
|
||||
params = site_params
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
@@ -185,7 +234,7 @@ class AdminAIService:
|
||||
f"""
|
||||
SELECT app_type, COUNT(*) AS cnt
|
||||
FROM biz.ai_run_logs
|
||||
WHERE created_at >= CURRENT_DATE - INTERVAL '6 days'
|
||||
WHERE {time_clause}
|
||||
{site_clause}
|
||||
GROUP BY app_type
|
||||
ORDER BY cnt DESC
|
||||
|
||||
Reference in New Issue
Block a user