feat: extend operational investigation workflows
This commit is contained in:
@@ -48,6 +48,7 @@ CREATE TABLE IF NOT EXISTS workbench.operational_task_runs (
|
||||
)),
|
||||
revision bigint NOT NULL CHECK (revision >= 1),
|
||||
agent_session_id text,
|
||||
agent_instance_id text,
|
||||
lease_expires_at timestamptz,
|
||||
heartbeat_at timestamptz,
|
||||
started_at timestamptz,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
-- Apply after 026, independently to every project business database.
|
||||
-- Preserve job identity, deduplication and audit metadata, including legacy results.
|
||||
ALTER TABLE workbench.calculation_jobs
|
||||
ADD COLUMN IF NOT EXISTS started_at timestamptz,
|
||||
ADD COLUMN IF NOT EXISTS finished_at timestamptz,
|
||||
ADD COLUMN IF NOT EXISTS queue_expires_at timestamptz,
|
||||
ADD COLUMN IF NOT EXISTS result_expires_at timestamptz;
|
||||
UPDATE workbench.calculation_jobs SET queue_expires_at=created_at+interval '1 hour'
|
||||
WHERE queue_expires_at IS NULL;
|
||||
UPDATE workbench.calculation_jobs SET finished_at=updated_at
|
||||
WHERE finished_at IS NULL AND status IN ('succeeded','failed','cancelled','timed_out','interrupted');
|
||||
-- Give pre-deployment results a complete retention window, even on reruns.
|
||||
UPDATE workbench.calculation_jobs SET result_expires_at=clock_timestamp()+interval '7 days'
|
||||
WHERE result IS NOT NULL AND result_expires_at IS NULL;
|
||||
ALTER TABLE workbench.calculation_jobs
|
||||
ALTER COLUMN queue_expires_at SET DEFAULT (clock_timestamp()+interval '1 hour'),
|
||||
ALTER COLUMN queue_expires_at SET NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS calculation_jobs_queue_expiry
|
||||
ON workbench.calculation_jobs(project_id,queue_expires_at) WHERE status='queued';
|
||||
CREATE INDEX IF NOT EXISTS calculation_jobs_result_expiry
|
||||
ON workbench.calculation_jobs(project_id,result_expires_at) WHERE result IS NOT NULL;
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Apply to every project business database before enabling task questions.
|
||||
CREATE TABLE IF NOT EXISTS workbench.operational_task_questions (
|
||||
project_id uuid NOT NULL,
|
||||
task_id uuid NOT NULL,
|
||||
question_request_id uuid NOT NULL,
|
||||
document jsonb NOT NULL,
|
||||
PRIMARY KEY (project_id, question_request_id),
|
||||
FOREIGN KEY (project_id, task_id)
|
||||
REFERENCES workbench.operational_tasks(project_id, task_id) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS operational_task_questions_task
|
||||
ON workbench.operational_task_questions(project_id, task_id);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS operational_task_questions_pending
|
||||
ON workbench.operational_task_questions(project_id, task_id)
|
||||
WHERE document->>'status' = 'pending';
|
||||
@@ -0,0 +1,141 @@
|
||||
-- Peripheral work orders are business-system records. Remove the former
|
||||
-- synthetic provenance branch from source rows and their task projections.
|
||||
|
||||
BEGIN;
|
||||
SET LOCAL lock_timeout = '5s';
|
||||
|
||||
CREATE FUNCTION pg_temp.normalize_peripheral_work_order_text(value jsonb)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
IMMUTABLE
|
||||
AS $$
|
||||
DECLARE
|
||||
normalized text := value::text;
|
||||
BEGIN
|
||||
normalized := replace(normalized, '对应外围记录明确标为 synthetic(系统测试)', '对应外围记录为 system_data 系统数据');
|
||||
normalized := replace(normalized, '有一条演练上报', '有一条系统上报');
|
||||
normalized := replace(normalized, '证据覆盖为 synthetic 上报工单快照', '证据覆盖为 system_data 上报工单快照');
|
||||
normalized := replace(normalized, '记录快照带 synthetic 标识', '记录快照为 system_data');
|
||||
normalized := replace(normalized, '外围工单结果注明为synthetic演练数据', '外围工单为system_data系统数据');
|
||||
normalized := replace(normalized, '工单为synthetic演练', '工单为system_data系统数据');
|
||||
normalized := replace(normalized, 'synthetic 爆管上报记录', '系统爆管上报记录');
|
||||
normalized := replace(normalized, '合成上报记录', '系统上报记录');
|
||||
normalized := replace(normalized, '外围模拟工单', '外围系统工单');
|
||||
normalized := replace(normalized, '外围记录为synthetic', '外围记录为system_data');
|
||||
normalized := replace(normalized, '证据快照整体为synthetic演练来源', '工单快照为system_data系统来源');
|
||||
normalized := replace(normalized, '来源标记为synthetic,仅能作为演练资料', '来源为system_data系统数据');
|
||||
normalized := replace(normalized, 'synthetic演练记录', '系统记录');
|
||||
normalized := replace(normalized, 'synthetic演练来源', 'system_data系统来源');
|
||||
normalized := replace(normalized, 'synthetic 演练来源', 'system_data 系统来源');
|
||||
normalized := replace(normalized, '外围样板合成摘要', '外围工单摘要');
|
||||
normalized := replace(normalized, '合成外围演练', '外围系统记录');
|
||||
normalized := replace(normalized, '合成外围', '外围');
|
||||
normalized := replace(normalized, '合成联调', '系统联调');
|
||||
normalized := replace(normalized, '合成演练', '系统测试');
|
||||
normalized := replace(normalized, '合成事件', '系统测试事件');
|
||||
RETURN normalized::jsonb;
|
||||
END
|
||||
$$;
|
||||
|
||||
UPDATE peripheral_sample.work_orders
|
||||
SET document = pg_temp.normalize_peripheral_work_order_text(
|
||||
jsonb_set(document, '{origin}', '"system_data"'::jsonb, true)
|
||||
)
|
||||
WHERE document->>'origin' IS DISTINCT FROM 'system_data'
|
||||
OR document::text ~* '(synthetic.*演练|synthetic 爆管上报|外围记录为synthetic|外围样板合成摘要|外围模拟工单|合成上报记录|合成外围|合成联调|合成事件)';
|
||||
|
||||
UPDATE peripheral_sample.work_order_revisions
|
||||
SET document = pg_temp.normalize_peripheral_work_order_text(
|
||||
jsonb_set(document, '{origin}', '"system_data"'::jsonb, true)
|
||||
)
|
||||
WHERE document->>'origin' IS DISTINCT FROM 'system_data'
|
||||
OR document::text ~* '(synthetic.*演练|synthetic 爆管上报|外围记录为synthetic|外围样板合成摘要|外围模拟工单|合成上报记录|合成外围|合成联调|合成事件)';
|
||||
|
||||
UPDATE peripheral_sample.requests
|
||||
SET result = pg_temp.normalize_peripheral_work_order_text(
|
||||
jsonb_set(result, '{origin}', '"system_data"'::jsonb, true)
|
||||
)
|
||||
WHERE command_key IN ('create_work_order', 'update_work_order')
|
||||
AND jsonb_typeof(result) = 'object'
|
||||
AND result ? 'work_order_id'
|
||||
AND (
|
||||
result->>'origin' IS DISTINCT FROM 'system_data'
|
||||
OR result::text ~* '(synthetic.*演练|synthetic 爆管上报|外围记录为synthetic|外围样板合成摘要|外围模拟工单|合成上报记录|合成外围|合成联调|合成事件)'
|
||||
);
|
||||
|
||||
UPDATE workbench.operational_task_external_feedback
|
||||
SET document = pg_temp.normalize_peripheral_work_order_text(jsonb_set(
|
||||
jsonb_set(
|
||||
jsonb_set(
|
||||
jsonb_set(
|
||||
document,
|
||||
'{work_order_snapshot,origin}',
|
||||
'"system_data"'::jsonb,
|
||||
false
|
||||
),
|
||||
'{evidence,kind}',
|
||||
'"external_feedback"'::jsonb,
|
||||
false
|
||||
),
|
||||
'{evidence,source_label}',
|
||||
'"外围工单"'::jsonb,
|
||||
false
|
||||
),
|
||||
'{detail}',
|
||||
to_jsonb(replace(COALESCE(document->>'detail', ''), '合成外围工单', '外围工单')),
|
||||
false
|
||||
))
|
||||
WHERE document ? 'work_order_snapshot';
|
||||
|
||||
UPDATE workbench.operational_task_evidence
|
||||
SET document = pg_temp.normalize_peripheral_work_order_text(jsonb_set(
|
||||
jsonb_set(
|
||||
document,
|
||||
'{kind}',
|
||||
'"external_feedback"'::jsonb,
|
||||
false
|
||||
),
|
||||
'{source_label}',
|
||||
'"外围工单"'::jsonb,
|
||||
false
|
||||
))
|
||||
WHERE document->>'source_ref' LIKE 'peripheral_sample:%'
|
||||
OR evidence_id LIKE 'provenance-correction:peripheral_sample:%';
|
||||
|
||||
UPDATE workbench.operational_tasks AS task
|
||||
SET document = pg_temp.normalize_peripheral_work_order_text(jsonb_set(
|
||||
task.document,
|
||||
'{summary}',
|
||||
to_jsonb(
|
||||
replace(
|
||||
replace(COALESCE(task.document->>'summary', ''), '合成外围工单', '外围工单'),
|
||||
'合成外围事件',
|
||||
'外围事件'
|
||||
)
|
||||
),
|
||||
false
|
||||
))
|
||||
FROM peripheral_sample.work_orders AS source_order
|
||||
WHERE task.project_id = source_order.project_id
|
||||
AND (
|
||||
task.document#>>'{source,external_id}' = source_order.work_order_id::text
|
||||
OR task.document#>>'{source,external_id}' =
|
||||
'peripheral_sample:' || source_order.work_order_id::text
|
||||
);
|
||||
|
||||
UPDATE workbench.operational_task_reports AS report
|
||||
SET document = pg_temp.normalize_peripheral_work_order_text(report.document)
|
||||
FROM workbench.operational_tasks AS task
|
||||
JOIN peripheral_sample.work_orders AS source_order
|
||||
ON task.project_id = source_order.project_id
|
||||
AND (
|
||||
task.document#>>'{source,external_id}' = source_order.work_order_id::text
|
||||
OR task.document#>>'{source,external_id}' =
|
||||
'peripheral_sample:' || source_order.work_order_id::text
|
||||
)
|
||||
WHERE report.project_id = task.project_id
|
||||
AND report.task_id = task.task_id
|
||||
AND report.document::text ~*
|
||||
'(synthetic.*演练|synthetic 爆管上报|外围记录为synthetic|外围样板合成摘要|外围模拟工单|合成上报记录|合成外围|合成联调|合成事件)';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Bind durable task runs to the Agent instance that owns their local session.
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE workbench.operational_task_runs
|
||||
ADD COLUMN IF NOT EXISTS agent_instance_id text;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS operational_task_runs_agent_owner_idx
|
||||
ON workbench.operational_task_runs(project_id,agent_instance_id,status,created_at,run_id)
|
||||
WHERE agent_instance_id IS NOT NULL
|
||||
AND status IN ('claimed','running');
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user