feat: extend operational investigation workflows
Generic Container CI/CD / test-build-publish (push) Successful in 3m53s
Server CI/CD v2 / build-test-publish-and-deploy (push) Successful in 3m52s

This commit is contained in:
2026-10-30 17:30:19 +08:00
parent 63af998045
commit 05183aff93
82 changed files with 4644 additions and 330 deletions
@@ -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;
+15
View File
@@ -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;