mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 00:31:58 +00:00
aa3bd65cfc
第 3 波的结构变化、取值观察、变化记录、定时维护都只有接口,这一提交给它们界面,能走通(收口): - 数据目录页左栏加第三个视图「变化」(view=changes):按要处理 / 提醒 / 说明分组(组内照服务端排好的先后),能按开着的 / 处理过的、结构变化 / 取值变化筛,筛选和打开的那一条记在地址里;视图标签上写几条要处理。点开一条,右栏写服务端的一句说法、 依据(谁、经什么测到的;取值变化写观察口径,结构变化写比对的两版结构)、前后各是什么、影响面(说到这些列的目录项和它们 现在的状态、写死了这张表的已发布模板、「这条 SQL 现在会报列不存在」、有效记录条件)、能做的处理。动作和做不了的原因都照 服务端给的 actions 画;清理目录项先确认,加入码值可以先填含义,误报必须写理由(写之前按钮不能点,服务端也会拒)。处理完 照实写结果:谁、什么时候、目录第几版、建了的任务(点得进起草、剖析的进度)。 - 表详情加「结构与取值变化」一节:这张表的变化(点「去处理」到「变化」视图里那一条)、撤销过的「已列全」、最近几次取值观察 (行数、码值分布、最新业务日期、按日行数)和各自的口径,口径换过的说一句不互相比较;按日行数的小柱图只给眼睛看,数字写在 字里和读屏名称里。 - 后台任务条(05 (g)):页头的「起草」「数据剖析」改回纯入口(进行中转圈、排队中时钟,读屏名称写状态、不写数字);DraftStrip 换成 JobStrip,按服务端给的同源队先后列出探查、起草、剖析,每项一行加进度条和提醒(剖析的「最近查询多数超时」也挪到这里, 窄屏、触屏看得见全文),「查看」打开对应的对话框,探查的到数据源卡片上(#source-<id> 滚过去)。 - 数据源卡片:要处理的变化条数的角标(读屏写全,点开到「变化」视图);「定时维护」对话框(和「探查范围」一样是卡片上的 独立对话框,不塞进编辑表单:两个保存混在一起出错时说不清哪一样没存上):开关缺省关、开启时提示选低峰时段,选步骤(PUT /maintenance),频率用 components/FreqPicker,保存成一条 target_kind=source_maintenance 的定时任务(新建 ScheduleTargetCreate, 改频率、开关 SchedulePatch 带版本);照实写下一次什么时候、最近一次建了哪些任务、哪几步没执行和原因(触发记录的 inputs), 剖析没开、调度没开时说到点会怎样。上传表格、记录表不给这一节。开着的维护在卡片上带一个标签写频率。 - 地址里带 pjob / djob 时打开那个剖析、起草任务的进度(定时维护的「最近一次」从数据源页链过来)。 新文件:typesSource.ts(接口约定)、api/sourceChanges.ts、lib/termsSource.ts(terms.ts 末尾转出)、pages/catalog/changes.ts、 ChangesQueue.tsx、ChangeDetail.tsx、TableChanges.tsx、JobStrip.tsx、pages/SourceMaintenanceDialog.tsx。变化的叫法和服务端逐字 一致,tests/test_source_change_terms.py 守着(维护步骤的叫法同样)。观察的按日行数服务端补上窗口里没数据的日子(不然小柱图 看不出断档)。
233 lines
7.8 KiB
TypeScript
233 lines
7.8 KiB
TypeScript
/**
|
||
* 数据源的变化、取值观察、定时维护、后台任务条的接口约定(docs/design/next-round/03-数据接入与目录维护.md B2–B4、05 (g))。
|
||
* 和后端 app/api/source_changes.py、app/data/source_changes.py(agentlab-change/1)、app/data/catalog_profile_observe.py 一一对应。
|
||
*
|
||
* 能不能做、依据什么、现在怎样都由服务端给(actions、basis_text、affects.catalog[*].now),界面只照写,不自己判。
|
||
*/
|
||
import type { Schedule, ScheduleFire } from './types'
|
||
|
||
// ---------------------------------------------------------------- 变化记录 agentlab-change/1
|
||
|
||
export type SourceChangeSeverity = 'info' | 'warning' | 'action'
|
||
export type SourceChangeStatus = 'open' | 'acknowledged' | 'resolved' | 'dismissed'
|
||
/** 结构变化 / 取值变化(叫法分开,和已有的「目录有变化」也分开,总方案 X10) */
|
||
export type SourceChangeCategory = 'struct' | 'value'
|
||
/** 清理目录项、加入码值、重新起草、重新剖析、知道了、误报(必须写理由) */
|
||
export type SourceChangeAction = 'clean_catalog' | 'add_codes' | 'redraft' | 'reprofile' | 'acknowledge' | 'dismiss'
|
||
/** 列表的状态筛选:开着的(含知道了还没处理的)、处理过的(解决了的、标为误报的) */
|
||
export type SourceChangeStatusFilter = 'pending' | 'handled'
|
||
|
||
/** 影响面里说到这些列的一个目录项(测到时的状态),now 是它现在的状态:清理过、不在目录里了为 null */
|
||
export interface SourceChangeCatalogRef {
|
||
table: string
|
||
path: string
|
||
label: string
|
||
status: string | null
|
||
source: string | null
|
||
/** 人工确认过的项还说着被删的列 */
|
||
needs_action?: boolean
|
||
now: { status: string | null; source: string | null } | null
|
||
}
|
||
|
||
export interface SourceChangeTemplateNode {
|
||
node_id: string
|
||
label: string | null
|
||
type: string
|
||
impact: 'direct' | 'possible'
|
||
/** 这条写死的 SQL 现在会报列不存在 */
|
||
breaks: boolean
|
||
unknown_columns?: string[]
|
||
}
|
||
|
||
/** 已发布模板里用到这张表的一个 */
|
||
export interface SourceChangeTemplate {
|
||
workflow_id: string
|
||
name: string
|
||
version: number
|
||
level: string
|
||
impact: 'direct' | 'possible'
|
||
nodes: SourceChangeTemplateNode[]
|
||
}
|
||
|
||
export interface SourceChangeAffects {
|
||
catalog: SourceChangeCatalogRef[]
|
||
templates: SourceChangeTemplate[]
|
||
/** 有效记录条件用到了这一列 */
|
||
rules_touched: boolean
|
||
}
|
||
|
||
/** 现在能做的一个处理动作;ok 为假时 reason 写为什么做不了 */
|
||
export interface SourceChangeActionOption {
|
||
action: SourceChangeAction
|
||
ok: boolean
|
||
reason: string | null
|
||
}
|
||
|
||
export interface SourceChangeResolution {
|
||
by: string | null
|
||
at: string
|
||
action: SourceChangeAction
|
||
note: string | null
|
||
catalog_version?: number
|
||
/** 别的表(指向它的关联关系)也动了的,各表的目录版本 */
|
||
catalog_versions?: Record<string, number>
|
||
job_id?: string
|
||
}
|
||
|
||
/** 谁、经什么测到的 */
|
||
export interface SourceChangeDetected {
|
||
job_kind: 'introspect' | 'profile' | 'on_demand' | string
|
||
job_id: string | null
|
||
task_seq: number | null
|
||
trigger: 'manual' | 'schedule' | 'on_demand' | string
|
||
actor: string | null
|
||
fire_at?: string
|
||
}
|
||
|
||
export interface SourceChange {
|
||
schema: string
|
||
seq: number
|
||
id: string
|
||
source_id: string
|
||
source_name: string
|
||
table: string | null
|
||
column: string | null
|
||
kind: string
|
||
category: SourceChangeCategory
|
||
severity: SourceChangeSeverity
|
||
/** 服务端给人看的一句(「orders.amount:删除了列」) */
|
||
summary: string
|
||
detected_at: string
|
||
last_seen_at: string
|
||
seen_count: number
|
||
detected_by: SourceChangeDetected
|
||
basis: { method?: string; key?: string; query_refs?: number[] } | null
|
||
/** 取值变化依据的口径(整表 / 窗口 / 块采样 / 前 N 行……);结构变化为 null(依据是前后两版结构) */
|
||
basis_text: string | null
|
||
before: any
|
||
after: any
|
||
affects: SourceChangeAffects
|
||
struct_version_before: number | null
|
||
struct_version_after: number | null
|
||
status: SourceChangeStatus
|
||
resolution: SourceChangeResolution | null
|
||
/** 现在能做的处理动作(处理过的为空) */
|
||
actions: SourceChangeActionOption[]
|
||
/** 处理时建的任务(重新起草、重新剖析) */
|
||
job: { kind: 'draft' | 'profile'; id: string } | null
|
||
}
|
||
|
||
export interface SourceChangeCounts {
|
||
/** 开着的和知道了还没处理的 */
|
||
pending: number
|
||
open: number
|
||
by_severity: Record<SourceChangeSeverity, number>
|
||
}
|
||
|
||
export interface SourceChangeList {
|
||
items: SourceChange[]
|
||
total: number
|
||
counts: SourceChangeCounts
|
||
}
|
||
|
||
export interface SourceChangeQuery {
|
||
status?: SourceChangeStatusFilter
|
||
category?: SourceChangeCategory | null
|
||
table?: string | null
|
||
limit?: number
|
||
offset?: number
|
||
}
|
||
|
||
export interface SourceChangeResolveBody {
|
||
action: SourceChangeAction
|
||
/** 误报必须写 */
|
||
note?: string
|
||
/** 加入码值:{码值: 含义},含义可以空 */
|
||
codes?: Record<string, string>
|
||
}
|
||
|
||
export interface SourceChangeResolveOut {
|
||
change: SourceChange
|
||
catalog_version?: number
|
||
catalog_versions?: Record<string, number>
|
||
job?: { kind: 'draft' | 'profile'; id: string }
|
||
}
|
||
|
||
// ---------------------------------------------------------------- 取值观察
|
||
|
||
export type ObservationKind = 'rows' | 'codes_observe' | 'freshness' | 'daily_volume'
|
||
|
||
/** 一次观察。data 的形状按种类:rows {rows, at_least, method}、codes_observe {values: [码值, 行数, 占比][], rows, truncated}、
|
||
* freshness {max}、daily_volume {since, until, days: [日期, 行数][], total, days_with_data} */
|
||
export interface ObservationPoint {
|
||
at: string | null
|
||
basis_key: string
|
||
/** 口径的说法(整表、业务日期 x 最近 35 天、块采样约 1%、按存储顺序取前 N 行……) */
|
||
basis_text: string
|
||
data: any
|
||
}
|
||
|
||
export interface ObservationSeries {
|
||
kind: ObservationKind
|
||
/** 行数是空串 */
|
||
column: string
|
||
/** 新的在前 */
|
||
points: ObservationPoint[]
|
||
/** 这几次的口径不全相同:口径不同不比 */
|
||
basis_changed: boolean
|
||
}
|
||
|
||
export interface TableObservations {
|
||
table: string
|
||
series: ObservationSeries[]
|
||
}
|
||
|
||
// ---------------------------------------------------------------- 定时维护
|
||
|
||
export type MaintenanceStep = 'introspect' | 'profile_needed' | 'observe'
|
||
|
||
/** 一次维护触发的 inputs:建了哪些任务、哪几步没执行和原因 */
|
||
export interface MaintenanceFireInputs {
|
||
steps?: MaintenanceStep[]
|
||
jobs?: { step: string; kind: 'introspect' | 'profile'; id: string; tables?: number; scope?: string }[]
|
||
skipped?: { step: MaintenanceStep; reason: string }[]
|
||
}
|
||
|
||
export interface MaintenanceSchedule extends Omit<Schedule, 'last_fire'> {
|
||
last_fire: (ScheduleFire & { inputs?: MaintenanceFireInputs }) | null
|
||
}
|
||
|
||
export interface SourceMaintenance {
|
||
steps: MaintenanceStep[]
|
||
profile_enabled: boolean
|
||
/** 上传表格、记录表不维护 */
|
||
maintained: boolean
|
||
/** 调度循环开着没有:关着时到点不会触发 */
|
||
scheduler_on: boolean
|
||
schedules: MaintenanceSchedule[]
|
||
}
|
||
|
||
/** 数据源列表一次取齐的:要处理的变化条数(角标)、指向它的维护定时 */
|
||
export interface SourceUpkeep {
|
||
source_id: string
|
||
changes: SourceChangeCounts
|
||
maintenance: { id: string; enabled: boolean; cron: string; timezone: string; description_text: string; next_run_at: string | null }[]
|
||
}
|
||
|
||
// ---------------------------------------------------------------- 后台任务条
|
||
|
||
export type SourceJobKind = 'introspect' | 'draft' | 'profile'
|
||
|
||
/** 这个源进行中和排队的一个后台任务,按同源队的先后排好 */
|
||
export interface SourceBackgroundJob {
|
||
kind: SourceJobKind
|
||
id: string
|
||
status: string
|
||
total: number
|
||
done: number
|
||
/** 排在谁后面(draft / profile / introspect / import / sync_draft) */
|
||
waiting_for: string | null
|
||
/** 在同源队里的位置(0 是正在做的);还没排进队为 null */
|
||
position: number | null
|
||
}
|