吸收数字员工策略治理审批路由收口
This commit is contained in:
@@ -246,10 +246,22 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
|
||||
private String policyEditStatus;
|
||||
@JsonProperty("policy_edit_reason")
|
||||
private String policyEditReason;
|
||||
@JsonProperty("merge_request_id")
|
||||
private String mergeRequestId;
|
||||
@JsonProperty("merge_recommendation")
|
||||
private String mergeRecommendation;
|
||||
@JsonProperty("remote_policy_edit_disabled")
|
||||
private Boolean remotePolicyEditDisabled;
|
||||
@JsonProperty("auto_merge_disabled")
|
||||
private Boolean autoMergeDisabled;
|
||||
@JsonProperty("approval_policy_edit_disabled")
|
||||
private Boolean approvalPolicyEditDisabled;
|
||||
@JsonProperty("route_policy_edit_disabled")
|
||||
private Boolean routePolicyEditDisabled;
|
||||
@JsonProperty("route_recovery_disabled")
|
||||
private Boolean routeRecoveryDisabled;
|
||||
@JsonProperty("high_risk_execution_disabled")
|
||||
private Boolean highRiskExecutionDisabled;
|
||||
@JsonProperty("schedule_id")
|
||||
private String scheduleId;
|
||||
@JsonProperty("job_id")
|
||||
|
||||
@@ -75,12 +75,13 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
"memory:archive_memory", "memory:restore_memory", "memory:mark_reviewed",
|
||||
"memory_policy:pull_policy", "memory_policy:mark_reviewed", "memory_policy:dismiss",
|
||||
"skill:mark_reviewed", "skill:dismiss",
|
||||
"policy_snapshot:pull_policy", "policy_snapshot:mark_reviewed", "policy_snapshot:dismiss",
|
||||
"governance_policy:pull_policy", "governance_policy:mark_reviewed", "governance_policy:dismiss",
|
||||
"policy_snapshot:pull_policy", "policy_snapshot:mark_reviewed", "policy_snapshot:dismiss", "policy_snapshot:request_policy_edit", "policy_snapshot:request_policy_merge_review",
|
||||
"governance_policy:pull_policy", "governance_policy:mark_reviewed", "governance_policy:dismiss", "governance_policy:request_policy_edit", "governance_policy:request_policy_merge_review",
|
||||
"scheduler:retry_scheduler_check", "scheduler:mark_reviewed", "scheduler:dismiss",
|
||||
"plan_step:mark_reviewed", "plan_step:dismiss", "plan_step:retry_policy_check",
|
||||
"plan:mark_reviewed", "plan:dismiss", "plan:request_revision_review", "plan:record_escalation",
|
||||
"revision:mark_reviewed", "revision:dismiss", "revision:request_revision_review",
|
||||
"route_decision:request_policy_edit", "route_decision:request_policy_merge_review",
|
||||
"diagnostic:mark_reviewed", "diagnostic:dismiss", "diagnostic:retry_check", "diagnostic:record_repair_intent",
|
||||
"audit:mark_reviewed", "audit:dismiss",
|
||||
"event:mark_reviewed", "event:dismiss"
|
||||
@@ -1024,6 +1025,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
private List<String> disabledAdminActionReasonCodes(String action) {
|
||||
return switch (StringUtils.trimToEmpty(action)) {
|
||||
case "edit_policy_remote" -> List.of("edit_policy_remote_disabled");
|
||||
case "auto_merge_policy" -> List.of("auto_merge_policy_disabled");
|
||||
case "auto_decide_approval" -> List.of("auto_decision_disabled");
|
||||
case "route_recover_execute" -> List.of("route_recovery_disabled");
|
||||
case "run_schedule_now" -> List.of("run_schedule_now_disabled");
|
||||
case "start_scheduler" -> List.of("start_scheduler_disabled");
|
||||
case "hard_interrupt" -> List.of("hard_interrupt_disabled");
|
||||
@@ -1198,8 +1202,14 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
.policyEditRequestId(firstString(businessView.get("policy_edit_request_id"), businessView.get("policyEditRequestId"), payload.get("policy_edit_request_id"), payload.get("policyEditRequestId")))
|
||||
.policyEditStatus(firstString(businessView.get("policy_edit_status"), businessView.get("policyEditStatus"), payload.get("policy_edit_status"), payload.get("policyEditStatus")))
|
||||
.policyEditReason(firstString(businessView.get("policy_edit_reason"), businessView.get("policyEditReason"), payload.get("policy_edit_reason"), payload.get("policyEditReason")))
|
||||
.mergeRequestId(firstString(businessView.get("merge_request_id"), businessView.get("mergeRequestId"), payload.get("merge_request_id"), payload.get("mergeRequestId")))
|
||||
.mergeRecommendation(firstString(businessView.get("merge_recommendation"), businessView.get("mergeRecommendation"), payload.get("merge_recommendation"), payload.get("mergeRecommendation")))
|
||||
.remotePolicyEditDisabled(nullableBooleanValue(firstPresent(businessView.get("remote_policy_edit_disabled"), businessView.get("remotePolicyEditDisabled"), payload.get("remote_policy_edit_disabled"), payload.get("remotePolicyEditDisabled"))))
|
||||
.autoMergeDisabled(nullableBooleanValue(firstPresent(businessView.get("auto_merge_disabled"), businessView.get("autoMergeDisabled"), payload.get("auto_merge_disabled"), payload.get("autoMergeDisabled"))))
|
||||
.approvalPolicyEditDisabled(nullableBooleanValue(firstPresent(businessView.get("approval_policy_edit_disabled"), businessView.get("approvalPolicyEditDisabled"), payload.get("approval_policy_edit_disabled"), payload.get("approvalPolicyEditDisabled"))))
|
||||
.routePolicyEditDisabled(nullableBooleanValue(firstPresent(businessView.get("route_policy_edit_disabled"), businessView.get("routePolicyEditDisabled"), payload.get("route_policy_edit_disabled"), payload.get("routePolicyEditDisabled"))))
|
||||
.routeRecoveryDisabled(nullableBooleanValue(firstPresent(businessView.get("route_recovery_disabled"), businessView.get("routeRecoveryDisabled"), payload.get("route_recovery_disabled"), payload.get("routeRecoveryDisabled"))))
|
||||
.highRiskExecutionDisabled(nullableBooleanValue(firstPresent(businessView.get("high_risk_execution_disabled"), businessView.get("highRiskExecutionDisabled"), payload.get("high_risk_execution_disabled"), payload.get("highRiskExecutionDisabled"))))
|
||||
.scheduleId(firstString(businessView.get("schedule_id"), businessView.get("scheduleId"), payload.get("schedule_id"), payload.get("scheduleId")))
|
||||
.jobId(firstString(businessView.get("job_id"), businessView.get("jobId"), payload.get("job_id"), payload.get("jobId")))
|
||||
.revisionId(firstString(businessView.get("revision_id"), businessView.get("revisionId"), payload.get("revision_id"), payload.get("revisionId")))
|
||||
@@ -1285,6 +1295,7 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
|| StringUtils.isNotBlank(row.getApprovalPolicyId())
|
||||
|| StringUtils.isNotBlank(row.getConflictPolicyId())
|
||||
|| StringUtils.isNotBlank(row.getDecisionGuardStatus())
|
||||
|| row.getApprovalPolicyEditDisabled() != null
|
||||
|| row.getBatchAcceptRemoteDisabled() != null
|
||||
|| row.getAutoDecisionDisabled() != null;
|
||||
}
|
||||
@@ -1385,7 +1396,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
|| StringUtils.equals(row.getCategory(), "route_intervention")
|
||||
|| StringUtils.equals(row.getCategory(), "governance")
|
||||
|| startsWithAny(row.getKind(), "route_", "governance_")
|
||||
|| StringUtils.isNotBlank(row.getRouteDecisionId());
|
||||
|| StringUtils.isNotBlank(row.getRouteDecisionId())
|
||||
|| row.getRoutePolicyEditDisabled() != null
|
||||
|| row.getRouteRecoveryDisabled() != null;
|
||||
}
|
||||
|
||||
private boolean isMemoryGovernanceRow(DigitalEmployeeAdminWorkbenchRowDto row) {
|
||||
@@ -1451,6 +1464,7 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
|| StringUtils.isNotBlank(row.getPolicyKind())
|
||||
|| StringUtils.isNotBlank(row.getPolicyKey())
|
||||
|| StringUtils.isNotBlank(row.getPolicyEditRequestId())
|
||||
|| StringUtils.isNotBlank(row.getMergeRequestId())
|
||||
|| row.getRemotePolicyEditDisabled() != null
|
||||
|| row.getAutoMergeDisabled() != null;
|
||||
}
|
||||
@@ -1519,7 +1533,8 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
|| contains(kind, "risk_guard_policy")
|
||||
|| StringUtils.isNotBlank(row.getGovernancePolicyId())
|
||||
|| StringUtils.isNotBlank(row.getPolicyGuardStatus())
|
||||
|| row.getHardInterruptDisabled() != null;
|
||||
|| row.getHardInterruptDisabled() != null
|
||||
|| row.getHighRiskExecutionDisabled() != null;
|
||||
}
|
||||
|
||||
private boolean isPlanRevisionRow(DigitalEmployeeAdminWorkbenchRowDto row) {
|
||||
|
||||
@@ -376,6 +376,7 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
Map.entry("decision_guard_status", "protected"),
|
||||
Map.entry("batch_accept_remote_disabled", true),
|
||||
Map.entry("auto_decision_disabled", true),
|
||||
Map.entry("approval_policy_edit_disabled", true),
|
||||
Map.entry("policy_reason", "manual_review_required"),
|
||||
Map.entry("policy_source", "admin"),
|
||||
Map.entry("policy_status", "synced")
|
||||
@@ -446,6 +447,7 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
assertThat(result.getRecords().get(0).getDecisionGuardStatus()).isEqualTo("protected");
|
||||
assertThat(result.getRecords().get(0).getBatchAcceptRemoteDisabled()).isTrue();
|
||||
assertThat(result.getRecords().get(0).getAutoDecisionDisabled()).isTrue();
|
||||
assertThat(result.getRecords().get(0).getApprovalPolicyEditDisabled()).isTrue();
|
||||
assertThat(result.getRecords().get(0).getPolicyReason()).isEqualTo("manual_review_required");
|
||||
assertThat(result.getRecords().get(1).getConflictPolicyId()).isEqualTo("conflict-policy-1");
|
||||
assertThat(result.getRecords().get(2).getApprovalPolicyId()).isEqualTo("risk-policy-1");
|
||||
@@ -453,6 +455,11 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
assertThat(result.getRecords().get(3).getTitle()).isEqualTo("裁决策略保护");
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminWorkbenchApprovalPoliciesReturnsDecisionGuardShellRows() {
|
||||
queryAdminWorkbenchApprovalPoliciesReturnsPolicyRowsOnly();
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminWorkbenchMemoryGovernanceReturnsMemoryRowsOnly() {
|
||||
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
||||
@@ -738,6 +745,8 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
Map.entry("policy_edit_request_id", "policy-edit-1"),
|
||||
Map.entry("policy_edit_status", "rejected"),
|
||||
Map.entry("policy_edit_reason", "manual_review_required"),
|
||||
Map.entry("merge_request_id", "merge-request-1"),
|
||||
Map.entry("merge_recommendation", "review_before_merge"),
|
||||
Map.entry("remote_policy_edit_disabled", true),
|
||||
Map.entry("auto_merge_disabled", true)
|
||||
),
|
||||
@@ -765,10 +774,17 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
assertThat(result.getRecords().get(2).getPolicyEditRequestId()).isEqualTo("policy-edit-1");
|
||||
assertThat(result.getRecords().get(2).getPolicyEditStatus()).isEqualTo("rejected");
|
||||
assertThat(result.getRecords().get(2).getPolicyEditReason()).isEqualTo("manual_review_required");
|
||||
assertThat(result.getRecords().get(2).getMergeRequestId()).isEqualTo("merge-request-1");
|
||||
assertThat(result.getRecords().get(2).getMergeRecommendation()).isEqualTo("review_before_merge");
|
||||
assertThat(result.getRecords().get(2).getRemotePolicyEditDisabled()).isTrue();
|
||||
assertThat(result.getRecords().get(2).getAutoMergeDisabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminWorkbenchPolicyCenterReturnsPolicyEditAndMergeShellRows() {
|
||||
queryAdminWorkbenchPolicyCenterReturnsPolicySnapshotRowsOnly();
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminWorkbenchSchedulerOperationsReturnsSchedulerRowsOnly() {
|
||||
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
||||
@@ -1034,7 +1050,8 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
"governance_policy_id", "governance-policy-1",
|
||||
"policy_guard_status", "guarded",
|
||||
"policy_reason", "manual_review_required",
|
||||
"hard_interrupt_disabled", true
|
||||
"hard_interrupt_disabled", true,
|
||||
"high_risk_execution_disabled", true
|
||||
),
|
||||
Map.of("id", "event-governance-policy-1", "kind", "governance_policy_snapshot")),
|
||||
record("outbox-manual-policy", "event", "event-governance-policy-2", 101L, new Date(11_000),
|
||||
@@ -1067,9 +1084,15 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
assertThat(result.getRecords().get(0).getPolicyGuardStatus()).isEqualTo("guarded");
|
||||
assertThat(result.getRecords().get(0).getPolicyReason()).isEqualTo("manual_review_required");
|
||||
assertThat(result.getRecords().get(0).getHardInterruptDisabled()).isTrue();
|
||||
assertThat(result.getRecords().get(0).getHighRiskExecutionDisabled()).isTrue();
|
||||
assertThat(result.getRecords().get(1).getGovernancePolicyId()).isEqualTo("manual-policy-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminWorkbenchGovernancePoliciesReturnsExecutionGuardRows() {
|
||||
queryAdminWorkbenchGovernancePoliciesReturnsPolicyRowsOnly();
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminWorkbenchPlanRevisionMaterializationReturnsRevisionRowsOnly() {
|
||||
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
||||
@@ -1310,6 +1333,8 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
"title", "路由策略阻断",
|
||||
"route_decision_id", "route-1",
|
||||
"reason", "route_action_policy_blocked",
|
||||
"route_policy_edit_disabled", true,
|
||||
"route_recovery_disabled", true,
|
||||
"summary", "控制动作被策略阻断"
|
||||
),
|
||||
Map.of("id", "event-route-1", "kind", "route_decision_blocked")),
|
||||
@@ -1358,10 +1383,17 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
assertThat(result.getRecords().get(0).getCategory()).isEqualTo("route_governance");
|
||||
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("blocked");
|
||||
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("控制动作被策略阻断");
|
||||
assertThat(result.getRecords().get(0).getRoutePolicyEditDisabled()).isTrue();
|
||||
assertThat(result.getRecords().get(0).getRouteRecoveryDisabled()).isTrue();
|
||||
assertThat(result.getRecords().get(1).getCategory()).isEqualTo("route_intervention");
|
||||
assertThat(result.getRecords().get(2).getRouteDecisionId()).isEqualTo("route-3");
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminWorkbenchRouteGovernanceReturnsRecoveryGuardRows() {
|
||||
queryAdminWorkbenchRouteGovernanceReturnsRouteAndGovernanceRowsOnly();
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminWorkbenchGovernanceCommandsReturnsGovernanceRowsOnly() {
|
||||
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
||||
@@ -2094,6 +2126,12 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
DigitalEmployeeAdminActionResultDto dismissPolicy = service.createAdminAction(
|
||||
adminActionRequest("governance_policy", "governance-policy-1", "dismiss")
|
||||
);
|
||||
DigitalEmployeeAdminActionResultDto requestPolicyEdit = service.createAdminAction(
|
||||
adminActionRequest("governance_policy", "governance-policy-1", "request_policy_edit")
|
||||
);
|
||||
DigitalEmployeeAdminActionResultDto requestPolicyMergeReview = service.createAdminAction(
|
||||
adminActionRequest("policy_snapshot", "route_decision", "request_policy_merge_review")
|
||||
);
|
||||
DigitalEmployeeAdminActionResultDto requestRevisionReview = service.createAdminAction(
|
||||
adminActionRequest("revision", "rev-1", "request_revision_review")
|
||||
);
|
||||
@@ -2101,11 +2139,18 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
assertThat(pullGovernancePolicy.getOk()).isTrue();
|
||||
assertThat(markPolicyReviewed.getOk()).isTrue();
|
||||
assertThat(dismissPolicy.getOk()).isTrue();
|
||||
assertThat(requestPolicyEdit.getOk()).isTrue();
|
||||
assertThat(requestPolicyMergeReview.getOk()).isTrue();
|
||||
assertThat(requestRevisionReview.getOk()).isTrue();
|
||||
assertThat(requestRevisionReview.getStatus()).isEqualTo("pending");
|
||||
assertThat(requestRevisionReview.getReasonCodes()).contains("action_recorded");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAdminActionAllowsLowRiskPolicyGovernanceIntents() {
|
||||
createAdminActionAllowsGovernancePolicyRevisionLowRiskActions();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAdminActionRejectsHighRiskGovernanceExecutionActions() {
|
||||
DigitalEmployeeAdminActionResultDto hardInterrupt = service.createAdminAction(
|
||||
@@ -2120,12 +2165,29 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
DigitalEmployeeAdminActionResultDto cancelTask = service.createAdminAction(
|
||||
adminActionRequest("governance_policy", "governance-policy-1", "cancel_task")
|
||||
);
|
||||
DigitalEmployeeAdminActionResultDto autoMerge = service.createAdminAction(
|
||||
adminActionRequest("policy_snapshot", "route_decision", "auto_merge_policy")
|
||||
);
|
||||
DigitalEmployeeAdminActionResultDto autoDecideApproval = service.createAdminAction(
|
||||
adminActionRequest("approval", "approval-1", "auto_decide_approval")
|
||||
);
|
||||
DigitalEmployeeAdminActionResultDto routeRecover = service.createAdminAction(
|
||||
adminActionRequest("route_decision", "route-1", "route_recover_execute")
|
||||
);
|
||||
|
||||
assertThat(hardInterrupt.getOk()).isFalse();
|
||||
assertThat(hardInterrupt.getReasonCodes()).contains("hard_interrupt_disabled");
|
||||
assertThat(activatePlan.getReasonCodes()).contains("high_risk_governance_action_disabled");
|
||||
assertThat(cancelRun.getReasonCodes()).contains("high_risk_governance_action_disabled");
|
||||
assertThat(cancelTask.getReasonCodes()).contains("high_risk_governance_action_disabled");
|
||||
assertThat(autoMerge.getReasonCodes()).contains("auto_merge_policy_disabled");
|
||||
assertThat(autoDecideApproval.getReasonCodes()).contains("auto_decision_disabled");
|
||||
assertThat(routeRecover.getReasonCodes()).contains("route_recovery_disabled");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAdminActionRejectsHighRiskPolicyGovernanceExecution() {
|
||||
createAdminActionRejectsHighRiskGovernanceExecutionActions();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user