吸收数字员工跨设备调度派发策略冲突预览
This commit is contained in:
@@ -51,6 +51,16 @@ public class DigitalEmployeePolicySnapshotRowDto {
|
||||
private Boolean autoDecisionDisabled;
|
||||
@JsonProperty("policy_reason")
|
||||
private String policyReason;
|
||||
@JsonProperty("dispatch_policy_key")
|
||||
private String dispatchPolicyKey;
|
||||
@JsonProperty("max_per_sweep")
|
||||
private Long maxPerSweep;
|
||||
@JsonProperty("auto_dispatch_ready_steps")
|
||||
private Boolean autoDispatchReadySteps;
|
||||
@JsonProperty("catch_up_on_startup")
|
||||
private Boolean catchUpOnStartup;
|
||||
@JsonProperty("max_run_history")
|
||||
private Long maxRunHistory;
|
||||
@JsonProperty("sync_record_url")
|
||||
private String syncRecordUrl;
|
||||
@JsonProperty("client_key_masked")
|
||||
|
||||
@@ -614,6 +614,11 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
.batchAcceptRemoteDisabled(nullableBooleanValue(firstPresent(latestView.get("batch_accept_remote_disabled"), latestView.get("batchAcceptRemoteDisabled"))))
|
||||
.autoDecisionDisabled(nullableBooleanValue(firstPresent(latestView.get("auto_decision_disabled"), latestView.get("autoDecisionDisabled"))))
|
||||
.policyReason(firstString(latestView.get("policy_reason"), latestView.get("policyReason")))
|
||||
.dispatchPolicyKey(firstString(latestView.get("dispatch_policy_key"), latestView.get("dispatchPolicyKey")))
|
||||
.maxPerSweep(numberValue(firstPresent(latestView.get("max_per_sweep"), latestView.get("maxPerSweep"))))
|
||||
.autoDispatchReadySteps(nullableBooleanValue(firstPresent(latestView.get("auto_dispatch_ready_steps"), latestView.get("autoDispatchReadySteps"))))
|
||||
.catchUpOnStartup(nullableBooleanValue(firstPresent(latestView.get("catch_up_on_startup"), latestView.get("catchUpOnStartup"))))
|
||||
.maxRunHistory(numberValue(firstPresent(latestView.get("max_run_history"), latestView.get("maxRunHistory"))))
|
||||
.syncRecordUrl(syncRecordUrl(latest.getOutboxId()))
|
||||
.clientKeyMasked(maskClientKey(latest.getClientKey()))
|
||||
.deviceId(latest.getDeviceId())
|
||||
@@ -687,7 +692,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
"policy_source",
|
||||
"auto_create_governance_commands",
|
||||
"max_per_sweep",
|
||||
"auto_dispatch_ready_steps",
|
||||
"catch_up_on_startup",
|
||||
"max_run_history",
|
||||
"approval_required_risk_levels",
|
||||
"approval_required_actions",
|
||||
"auto_reject_actions",
|
||||
|
||||
@@ -1882,6 +1882,82 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
assertThat(row.getRecommendedResolution()).isEqualTo("review_latest_policy_snapshot");
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminPolicySnapshotsSummarizesDispatchAndSchedulerPolicyConflicts() {
|
||||
DigitalEmployeeSyncRecord dispatchA = record("outbox-dispatch-policy-a", "event", "event-dispatch-policy-a", 101L, new Date(10_000),
|
||||
Map.of(
|
||||
"entity_type", "event",
|
||||
"category", "policy_snapshot",
|
||||
"kind", "plan_step_dispatch_policy_pulled",
|
||||
"policy_kind", "dispatch",
|
||||
"policy_key", "plan_step_dispatch",
|
||||
"enabled", true,
|
||||
"max_per_sweep", 3,
|
||||
"auto_dispatch_ready_steps", true,
|
||||
"dispatch_policy_key", "plan_step_dispatch"
|
||||
),
|
||||
Map.of("kind", "plan_step_dispatch_policy_pulled"));
|
||||
dispatchA.setDeviceId("device-a");
|
||||
DigitalEmployeeSyncRecord dispatchB = record("outbox-dispatch-policy-b", "event", "event-dispatch-policy-b", 101L, new Date(11_000),
|
||||
Map.of(
|
||||
"entity_type", "event",
|
||||
"category", "policy_snapshot",
|
||||
"kind", "plan_step_dispatch_policy_pulled",
|
||||
"policy_kind", "dispatch",
|
||||
"policy_key", "plan_step_dispatch",
|
||||
"enabled", true,
|
||||
"max_per_sweep", 8,
|
||||
"auto_dispatch_ready_steps", false,
|
||||
"dispatch_policy_key", "plan_step_dispatch"
|
||||
),
|
||||
Map.of("kind", "plan_step_dispatch_policy_pulled"));
|
||||
dispatchB.setDeviceId("device-b");
|
||||
DigitalEmployeeSyncRecord schedulerA = record("outbox-scheduler-policy-a", "event", "event-scheduler-policy-a", 101L, new Date(12_000),
|
||||
Map.of(
|
||||
"entity_type", "event",
|
||||
"category", "policy_snapshot",
|
||||
"kind", "scheduler_policy_snapshot",
|
||||
"policy_kind", "scheduler",
|
||||
"policy_key", "scheduler",
|
||||
"enabled", true,
|
||||
"catch_up_on_startup", true,
|
||||
"max_run_history", 20
|
||||
),
|
||||
Map.of("kind", "scheduler_policy_snapshot"));
|
||||
schedulerA.setDeviceId("device-a");
|
||||
DigitalEmployeeSyncRecord schedulerB = record("outbox-scheduler-policy-b", "event", "event-scheduler-policy-b", 101L, new Date(13_000),
|
||||
Map.of(
|
||||
"entity_type", "event",
|
||||
"category", "policy_snapshot",
|
||||
"kind", "scheduler_policy_snapshot",
|
||||
"policy_kind", "scheduler",
|
||||
"policy_key", "scheduler",
|
||||
"enabled", true,
|
||||
"catch_up_on_startup", false,
|
||||
"max_run_history", 50
|
||||
),
|
||||
Map.of("kind", "scheduler_policy_snapshot"));
|
||||
schedulerB.setDeviceId("device-b");
|
||||
|
||||
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq("event"), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(100L)))
|
||||
.thenReturn(page(List.of(dispatchA, dispatchB, schedulerA, schedulerB)));
|
||||
|
||||
DigitalEmployeePolicySnapshotPageDto dispatchResult = service.queryAdminPolicySnapshots(null, null, "conflict", "dispatch", null, null, 1L, 20L);
|
||||
DigitalEmployeePolicySnapshotPageDto schedulerResult = service.queryAdminPolicySnapshots(null, null, "conflict", "scheduler", null, null, 1L, 20L);
|
||||
|
||||
DigitalEmployeePolicySnapshotRowDto dispatchRow = dispatchResult.getRecords().get(0);
|
||||
assertThat(dispatchRow.getPolicyKind()).isEqualTo("dispatch");
|
||||
assertThat(dispatchRow.getConflictKeys()).contains("max_per_sweep", "auto_dispatch_ready_steps");
|
||||
assertThat(dispatchRow.getDispatchPolicyKey()).isEqualTo("plan_step_dispatch");
|
||||
assertThat(dispatchRow.getMaxPerSweep()).isEqualTo(8L);
|
||||
assertThat(dispatchRow.getAutoDispatchReadySteps()).isFalse();
|
||||
DigitalEmployeePolicySnapshotRowDto schedulerRow = schedulerResult.getRecords().get(0);
|
||||
assertThat(schedulerRow.getPolicyKind()).isEqualTo("scheduler");
|
||||
assertThat(schedulerRow.getConflictKeys()).contains("catch_up_on_startup", "max_run_history");
|
||||
assertThat(schedulerRow.getCatchUpOnStartup()).isFalse();
|
||||
assertThat(schedulerRow.getMaxRunHistory()).isEqualTo(50L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordDailyReportSendResultStoresRecordedObservation() {
|
||||
DigitalEmployeeAdminRecordRequestDto request = adminRecordRequest("daily_report", "report-1");
|
||||
|
||||
@@ -726,6 +726,11 @@ const DigitalEmployeeOps: React.FC = () => {
|
||||
batch_accept_remote_disabled: record.batch_accept_remote_disabled,
|
||||
auto_decision_disabled: record.auto_decision_disabled,
|
||||
policy_reason: record.policy_reason,
|
||||
dispatch_policy_key: record.dispatch_policy_key,
|
||||
max_per_sweep: record.max_per_sweep,
|
||||
auto_dispatch_ready_steps: record.auto_dispatch_ready_steps,
|
||||
catch_up_on_startup: record.catch_up_on_startup,
|
||||
max_run_history: record.max_run_history,
|
||||
latest_synced_at: record.latest_synced_at,
|
||||
synced_at: record.latest_synced_at,
|
||||
client_key_masked: record.client_key_masked,
|
||||
@@ -902,10 +907,26 @@ const DigitalEmployeeOps: React.FC = () => {
|
||||
` · 跨设备路由干预冲突 ${detailRecord.intervention_conflict_status}`}
|
||||
{(detailRecord.approval_policy_id || detailRecord.conflict_policy_id || detailRecord.decision_guard_status) &&
|
||||
` · 跨设备审批策略冲突`}
|
||||
{(detailRecord.policy_kind === 'dispatch' ||
|
||||
detailRecord.dispatch_policy_key ||
|
||||
detailRecord.max_per_sweep != null ||
|
||||
detailRecord.auto_dispatch_ready_steps != null) &&
|
||||
` · 跨设备派发策略冲突`}
|
||||
{(detailRecord.policy_kind === 'scheduler' ||
|
||||
detailRecord.catch_up_on_startup != null ||
|
||||
detailRecord.max_run_history != null) &&
|
||||
` · 跨设备调度策略冲突`}
|
||||
{detailRecord.approval_policy_id && ` · 审批策略 ${detailRecord.approval_policy_id}`}
|
||||
{detailRecord.conflict_policy_id && ` · 冲突策略 ${detailRecord.conflict_policy_id}`}
|
||||
{detailRecord.decision_guard_status && ` · 裁决保护 ${detailRecord.decision_guard_status}`}
|
||||
{detailRecord.policy_reason && ` · 策略原因 ${detailRecord.policy_reason}`}
|
||||
{detailRecord.dispatch_policy_key && ` · 派发策略 ${detailRecord.dispatch_policy_key}`}
|
||||
{detailRecord.max_per_sweep != null && ` · max_per_sweep ${detailRecord.max_per_sweep}`}
|
||||
{detailRecord.auto_dispatch_ready_steps != null &&
|
||||
` · auto_dispatch_ready_steps ${detailRecord.auto_dispatch_ready_steps ? '开启' : '关闭'}`}
|
||||
{detailRecord.catch_up_on_startup != null &&
|
||||
` · catch_up_on_startup ${detailRecord.catch_up_on_startup ? '开启' : '关闭'}`}
|
||||
{detailRecord.max_run_history != null && ` · max_run_history ${detailRecord.max_run_history}`}
|
||||
{detailRecord.batch_accept_remote_disabled && ' · 批量采纳远端禁用'}
|
||||
{detailRecord.auto_decision_disabled && ' · 自动裁决禁用'}
|
||||
{detailRecord.route_decision_count != null &&
|
||||
|
||||
@@ -600,6 +600,10 @@ export interface DigitalEmployeeAdminWorkbenchRow {
|
||||
lease_source?: string;
|
||||
dispatch_status?: string;
|
||||
dispatch_policy_key?: string;
|
||||
max_per_sweep?: number;
|
||||
auto_dispatch_ready_steps?: boolean;
|
||||
catch_up_on_startup?: boolean;
|
||||
max_run_history?: number;
|
||||
orchestration_id?: string;
|
||||
trigger_source?: string;
|
||||
approval_id?: string;
|
||||
@@ -728,6 +732,11 @@ export interface DigitalEmployeePolicySnapshotRow {
|
||||
batch_accept_remote_disabled?: boolean;
|
||||
auto_decision_disabled?: boolean;
|
||||
policy_reason?: string;
|
||||
dispatch_policy_key?: string;
|
||||
max_per_sweep?: number;
|
||||
auto_dispatch_ready_steps?: boolean;
|
||||
catch_up_on_startup?: boolean;
|
||||
max_run_history?: number;
|
||||
sync_record_url?: string;
|
||||
client_key_masked?: string;
|
||||
device_id?: string;
|
||||
|
||||
@@ -1283,18 +1283,25 @@ function checkDigitalAdminPolicySnapshots() {
|
||||
[backendDto, "intervention_conflict_status", "backend route intervention conflict status field"],
|
||||
[backendDto, "approval_policy_id", "backend policy snapshot approval policy field"],
|
||||
[backendDto, "auto_decision_disabled", "backend policy snapshot auto decision field"],
|
||||
[backendDto, "max_per_sweep", "backend policy snapshot max per sweep field"],
|
||||
[backendDto, "catch_up_on_startup", "backend policy snapshot catch up field"],
|
||||
[backendDto, "route_decision_count", "backend route decision count field"],
|
||||
[backendTest, "queryAdminPolicySnapshotsSummarizesRouteInterventionConflicts", "backend route intervention conflict test"],
|
||||
[backendTest, "queryAdminPolicySnapshotsSummarizesApprovalPolicyConflicts", "backend approval policy conflict test"],
|
||||
[backendTest, "queryAdminPolicySnapshotsSummarizesDispatchAndSchedulerPolicyConflicts", "backend dispatch scheduler policy conflict test"],
|
||||
[qimingService, "apiDigitalEmployeeAdminPolicySnapshots", "qiming policy snapshot service"],
|
||||
[qimingService, "/api/digital-employee/admin/policies/snapshots", "qiming policy snapshot endpoint"],
|
||||
[qimingTypes, "DigitalEmployeePolicySnapshotRow", "qiming policy snapshot row type"],
|
||||
[qimingTypes, "policy_conflicts", "qiming policy conflicts view type"],
|
||||
[qimingTypes, "approval_policy_id", "qiming approval policy snapshot type field"],
|
||||
[qimingTypes, "max_per_sweep", "qiming dispatch policy snapshot type field"],
|
||||
[qimingTypes, "catch_up_on_startup", "qiming scheduler policy snapshot type field"],
|
||||
[qimingTypes, "intervention_conflict_status", "qiming route intervention conflict type field"],
|
||||
[qimingOps, "策略冲突", "qiming policy conflict tab text"],
|
||||
[qimingOps, "conflict_keys", "qiming conflict key display"],
|
||||
[qimingOps, "跨设备审批策略冲突", "qiming approval policy conflict copy"],
|
||||
[qimingOps, "跨设备派发策略冲突", "qiming dispatch policy conflict copy"],
|
||||
[qimingOps, "跨设备调度策略冲突", "qiming scheduler policy conflict copy"],
|
||||
[qimingOps, "裁决保护", "qiming decision guard conflict copy"],
|
||||
[qimingOps, "跨设备路由干预冲突", "qiming route intervention conflict copy"],
|
||||
[qimingOps, "不恢复执行", "qiming route recovery guard copy"],
|
||||
@@ -1302,6 +1309,7 @@ function checkDigitalAdminPolicySnapshots() {
|
||||
[qimingOps, "不远程改策略", "qiming remote policy edit guard copy"],
|
||||
[docs, "跨设备策略冲突视图", "docs policy conflict absorption"],
|
||||
[docs, "跨设备审批策略冲突预览", "docs approval policy conflict absorption"],
|
||||
[docs, "跨设备调度派发策略冲突预览", "docs dispatch scheduler policy conflict absorption"],
|
||||
[docs, "跨设备路由干预冲突可视化", "docs route intervention conflict absorption"],
|
||||
];
|
||||
const missing = requiredSnippets
|
||||
|
||||
@@ -551,13 +551,13 @@ GET /api/digital-employee/approvals
|
||||
1. **PlanStep 与依赖图(依赖图调度已开始)**
|
||||
- 已吸收:Plan / Task / Run 记录、计划模板、`create_plan` 中的 steps/tasks 可物化为任务;PlanStep 已开始作为正式本地实体落入 `digital_plan_steps`。
|
||||
- 当前能力:PlanStep 会进入 `digital_sync_outbox`,entity type 为 `plan_step`;任务中心 flow 和 debug store 优先读取真实 PlanStep 生成步骤图;Task Agent 的 retry / skip / cancel / pause / resume / input / run 控制已可更新真实 Task、PlanStep、Run、Event 和 outbox;前置步骤跳过、取消或重试后会重新评估后继步骤,推进为 ready / blocked / pending 并写入依赖图事件;scheduler sweep 会识别可派发的 ready PlanStep,派发前先通过管理端 `POST /api/digital-employee/leases/plan-step-dispatch/acquire` 做跨设备强租约仲裁,管理端拒绝会以 `remote_lease_rejected` 跳过,管理端异常会降级为 5 分钟本地软租约 `payload.dispatchLease.source = local_fallback` 并记录 `remote_error`;调用本地 `/computer/chat` 后会写入 `plan_step_dispatch_*` 与 `governance_start_run` 事件,派发完成或失败会先尝试 `release` 管理端租约再释放本地 lease 并写入 `plan_step_lease_*` 事件;已有未过期租约的步骤仍会以 `lease_active` 跳过;auto sweep 会按节流从管理端 `GET /api/digital-employee/policies/plan-step-dispatch` 拉取远端派发策略,拉取失败时保留本地策略并记录 `last_pull_error`;embedded 已提供 `/api/digital-employee/plan-steps`、`/api/digital-employee/plan-step-graph`、`/api/digital-employee/plans/:planId/dispatch-ready-steps`、`/api/plan-step/dispatch-policy` 和 `/api/plan-step/dispatch-policy/pull`,ready PlanStep 安全派发、计划级跨任务推进、管理端依赖图视图、本地/远端派发策略、可观察租约状态和首页阻塞依赖处理入口已开始闭环。派发策略管理 UI 已开始吸收,embedded 新增“策略中心”集中展示和编辑 `enabled/max_per_sweep/auto_dispatch_ready_steps`。正式管理端策略中心预览已开始吸收,qiming-backend 新增 `policy_center` 运营台视图聚合派发、风险审批、入口路由和技能策略快照,qiming“数字员工运营台”的“策略中心”tab 可记录批量拉取策略、标记已看和忽略意图,不开放远程策略编辑。正式管理端步骤调度预览已开始吸收,qiming“数字员工运营台”的“步骤调度”tab 会聚合 PlanStep fact、依赖状态、租约、派发事件和策略拉取审计,只记录标记已看、忽略和重试策略检查意图,不远程派发、不抢占租约、不释放租约。
|
||||
- 后续缺口:跨设备审批策略冲突预览已开始吸收,策略冲突页可展示审批策略、冲突策略、裁决保护和自动裁决保护差异;远程策略编辑安全模型、真实派发/租约裁决和跨设备策略自动合并仍待吸收。
|
||||
- 后续缺口:跨设备审批策略冲突预览已开始吸收,策略冲突页可展示审批策略、冲突策略、裁决保护和自动裁决保护差异;跨设备调度派发策略冲突预览已开始吸收,策略冲突页可展示 `max_per_sweep`、`auto_dispatch_ready_steps`、`catch_up_on_startup` 和 `max_run_history` 差异;远程策略编辑安全模型、真实派发/租约裁决和跨设备策略自动合并仍待吸收。
|
||||
- 建议:下一轮围绕管理端正式路由 UI 或跨端审批策略 UI,把本地可治理调度继续推进到跨端治理策略。
|
||||
|
||||
2. **调度 / 定时 / 周期任务**
|
||||
- 已吸收:`digital_schedules`、`digital_schedule_runs` 已进入 qimingclaw 本地 SQLite 与 outbox,entity type 为 `schedule` / `schedule_run`;旧 `/api/cron`、`/api/scheduler/jobs` 和治理命令会优先读取真实本地调度记录。
|
||||
- 当前能力:主进程 `DigitalEmployeeScheduler` 可按本机 5 字段 cron 到点触发本地 `/computer/chat`,支持启动 catch-up、立即运行、暂停/恢复/删除、失败重试、运行历史和同步诊断。多调度并发策略 UI 已开始吸收,embedded 新增“调度运营”入口,可查看 scheduler jobs、最近运行、`catch_up_on_startup`、`max_run_history`,并触发一次立即检查调度。正式管理端调度运营预览已开始吸收,qiming-backend 新增 `scheduler_operations` 运营台视图聚合 scheduler job、cron settings、lease、dispatch sweep 和 recent run 摘要,qiming“数字员工运营台”的“调度运营”tab 只开放立即检查调度、标记已看和忽略意图,不开放 start/stop 或高风险立即运行。
|
||||
- 后续缺口:更细的秒级 cron、复杂日历排除规则、正式外部管理端调度策略下发和跨设备调度冲突合并仍待吸收。
|
||||
- 后续缺口:跨设备调度派发策略冲突预览已开始吸收,管理端策略冲突页只读展示调度 catch-up、运行历史和派发 sweep 策略差异,不立即调度、不接管租约、不自动合并策略;更细的秒级 cron、复杂日历排除规则、正式外部管理端调度策略下发和跨设备调度冲突合并仍待吸收。
|
||||
- 建议:下一轮围绕入口路由/任务分流,把 schedule 触发的计划与具体 Skill Policy、Task Agent 状态机更精确地绑定。
|
||||
|
||||
3. **MemoryEntry / 长期记忆(已开始)**
|
||||
@@ -609,7 +609,7 @@ GET /api/digital-employee/approvals
|
||||
- 建议:下一轮围绕管理端正式审计视图和诊断修复动作,把本地可追溯审计继续推进到可运营处置。
|
||||
|
||||
12. **管理端业务查询模型**
|
||||
- 已吸收:管理端已有通用 sync record 接收、查询、payload 摘要和深链;后端 sync record 已开始保存客户端顶层 `contract_version`、`entity_summary` 和 `business_view`,并基于现有 `digital_employee_sync_record` 拆出 `/api/digital-employee/plans`、`/plans/{plan_id}`、`/tasks`、`/runs`、`/events`、`/artifacts`、`/approvals` 管理端业务查询模型;列表支持客户端 Key、设备、实体 ID、状态、同步状态和同步时间范围过滤,业务 row 会提炼 title/status/summary、Plan/Task/Run 关联、发生/开始/结束时间、sync record 深链和脱敏客户端 Key;Plan 视图会聚合 task/run 计数与最近事件,Plan 详情会返回关联 tasks/runs/events/artifacts/approvals 摘要。embedded adapter 已拆出同名只读业务查询接口,从 qimingclaw runtime、artifact、approval 和 canonical event 投影生成统一分页视图;embedded 数字员工页已新增“业务视图”入口,支持计划/任务/运行/事件/产物/审批分段、实体/状态/同步状态/时间筛选、分页和详情 JSON 查看;客户端 outbox 的 event `business_view` 已开始按 route decision、governance command、approval action、artifact lifecycle/access、skill call audit 和 ready PlanStep dispatch 细分常用字段,本地与管理端业务视图投影已开始闭环。正式外部管理端台面已开始吸收:qiming-backend 新增 `/api/digital-employee/admin/workbench/{view}`,qiming 管理端新增“数字员工运营台”,统一展示业务视图、介入台、产物治理、通知运营、审计诊断、日报运营和路由治理,只读消费 sync record `business_view` 并提供同步记录深链。管理端低风险动作闭环已开始吸收:后端新增 `/api/digital-employee/admin/actions` 记录动作意图和 `/pending` 拉取队列,qimingclaw 只应用保留本地、标记复核、通知已读/忽略、产物保留/到期、日报交付/确认/审批请求等低风险动作并写入 `admin_action_applied` / `admin_action_rejected` / `admin_action_failed`,qiming 运营台抽屉只提示“已记录,等待客户端拉取”。跨设备策略冲突视图已开始吸收:qimingclaw 将派发、风险审批和入口路由策略同步事件投影为 `policy_snapshot` business view,后端新增 `/api/digital-employee/admin/policies/snapshots` 聚合 client/device 维度差异并输出 `conflict_keys`,qiming 运营台新增“策略冲突” tab 展示 policy drift 与 sync record 深链。跨设备审批策略冲突预览已开始吸收:策略冲突页会把 `approval_policy_id`、`conflict_policy_id`、`decision_guard_status`、`batch_accept_remote_disabled`、`auto_decision_disabled` 和策略原因纳入冲突字段和详情解释,但不自动合并策略、不远程编辑策略。正式管理端策略中心预览和正式管理端调度运营预览已开始吸收:`admin/workbench` 新增 `policy_center` 与 `scheduler_operations` 视图,统一消费策略快照、scheduler job、cron settings、lease、dispatch sweep 和 recent run 摘要,并通过低风险 admin action 记录策略拉取、立即检查调度、复核和忽略意图。业务事实物化查询已开始吸收:后端新增 `digital_employee_business_fact`、`digital_employee_artifact_lifecycle`、`digital_employee_daily_report_fact` 三张增量物化表,同步入库时 upsert 安全业务摘要,业务查询优先返回 `materialized: true` 行,旧记录继续回退 sync record。
|
||||
- 已吸收:管理端已有通用 sync record 接收、查询、payload 摘要和深链;后端 sync record 已开始保存客户端顶层 `contract_version`、`entity_summary` 和 `business_view`,并基于现有 `digital_employee_sync_record` 拆出 `/api/digital-employee/plans`、`/plans/{plan_id}`、`/tasks`、`/runs`、`/events`、`/artifacts`、`/approvals` 管理端业务查询模型;列表支持客户端 Key、设备、实体 ID、状态、同步状态和同步时间范围过滤,业务 row 会提炼 title/status/summary、Plan/Task/Run 关联、发生/开始/结束时间、sync record 深链和脱敏客户端 Key;Plan 视图会聚合 task/run 计数与最近事件,Plan 详情会返回关联 tasks/runs/events/artifacts/approvals 摘要。embedded adapter 已拆出同名只读业务查询接口,从 qimingclaw runtime、artifact、approval 和 canonical event 投影生成统一分页视图;embedded 数字员工页已新增“业务视图”入口,支持计划/任务/运行/事件/产物/审批分段、实体/状态/同步状态/时间筛选、分页和详情 JSON 查看;客户端 outbox 的 event `business_view` 已开始按 route decision、governance command、approval action、artifact lifecycle/access、skill call audit 和 ready PlanStep dispatch 细分常用字段,本地与管理端业务视图投影已开始闭环。正式外部管理端台面已开始吸收:qiming-backend 新增 `/api/digital-employee/admin/workbench/{view}`,qiming 管理端新增“数字员工运营台”,统一展示业务视图、介入台、产物治理、通知运营、审计诊断、日报运营和路由治理,只读消费 sync record `business_view` 并提供同步记录深链。管理端低风险动作闭环已开始吸收:后端新增 `/api/digital-employee/admin/actions` 记录动作意图和 `/pending` 拉取队列,qimingclaw 只应用保留本地、标记复核、通知已读/忽略、产物保留/到期、日报交付/确认/审批请求等低风险动作并写入 `admin_action_applied` / `admin_action_rejected` / `admin_action_failed`,qiming 运营台抽屉只提示“已记录,等待客户端拉取”。跨设备策略冲突视图已开始吸收:qimingclaw 将派发、风险审批和入口路由策略同步事件投影为 `policy_snapshot` business view,后端新增 `/api/digital-employee/admin/policies/snapshots` 聚合 client/device 维度差异并输出 `conflict_keys`,qiming 运营台新增“策略冲突” tab 展示 policy drift 与 sync record 深链。跨设备审批策略冲突预览已开始吸收:策略冲突页会把 `approval_policy_id`、`conflict_policy_id`、`decision_guard_status`、`batch_accept_remote_disabled`、`auto_decision_disabled` 和策略原因纳入冲突字段和详情解释,但不自动合并策略、不远程编辑策略。跨设备调度派发策略冲突预览已开始吸收:策略冲突页会把 `dispatch_policy_key`、`max_per_sweep`、`auto_dispatch_ready_steps`、`catch_up_on_startup` 和 `max_run_history` 纳入冲突字段和详情解释,但不立即运行、不接管租约、不远程改策略。正式管理端策略中心预览和正式管理端调度运营预览已开始吸收:`admin/workbench` 新增 `policy_center` 与 `scheduler_operations` 视图,统一消费策略快照、scheduler job、cron settings、lease、dispatch sweep 和 recent run 摘要,并通过低风险 admin action 记录策略拉取、立即检查调度、复核和忽略意图。业务事实物化查询已开始吸收:后端新增 `digital_employee_business_fact`、`digital_employee_artifact_lifecycle`、`digital_employee_daily_report_fact` 三张增量物化表,同步入库时 upsert 安全业务摘要,业务查询优先返回 `materialized: true` 行,旧记录继续回退 sync record。
|
||||
- 缺口:复杂组合检索、跨设备聚合图、远程裁决/策略编辑动作和物化业务表仍待吸收。
|
||||
- 建议:先使用 sync record 派生业务查询模型和 embedded 业务视图预览承接联调,再按容量和查询压力决定是否拆 Plan / Task / Run / Event 物理业务表。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user