吸收数字员工治理审计补齐
This commit is contained in:
@@ -3387,7 +3387,12 @@ function routeDecisionFromRuntimePayload(payload: Record<string, unknown>, event
|
||||
function routeDecisionAttentionLevel(decision: RouteDecisionRecord): 'info' | 'action' | 'warn' | 'error' {
|
||||
if (decision.policy_result === 'approval_required') return 'action';
|
||||
if (decision.policy_result && decision.policy_result !== 'accepted') return 'error';
|
||||
if (decision.reason_codes.includes('candidate_skills_disabled') || decision.reason_codes.includes('route_action_missing_context')) return 'warn';
|
||||
if (
|
||||
decision.reason_codes.includes('candidate_skills_disabled')
|
||||
|| decision.reason_codes.includes('route_action_missing_context')
|
||||
|| decision.reason_codes.includes('route_action_policy_blocked')
|
||||
|| decision.reason_codes.includes('route_action_not_mapped')
|
||||
) return 'warn';
|
||||
if (decision.created_command_id) return 'action';
|
||||
return 'info';
|
||||
}
|
||||
@@ -3412,6 +3417,13 @@ function buildRouteDecisionSummary(snapshot: QimingclawSnapshot | null): Digital
|
||||
return {
|
||||
total: rows.length,
|
||||
mapped_count: rows.filter((row) => stringValue(row.created_command_id)).length,
|
||||
governance_mapped_count: rows.filter((row) => stringValue(row.created_command_id)).length,
|
||||
governance_blocked_count: rows.filter((row) => {
|
||||
const reasonCodes = arrayValue(row.reason_codes).map(stringValue);
|
||||
return reasonCodes.includes('route_action_policy_blocked')
|
||||
|| reasonCodes.includes('route_action_missing_context')
|
||||
|| reasonCodes.includes('route_action_not_mapped');
|
||||
}).length,
|
||||
attention_count: rows.filter((row) => ['warn', 'error'].includes(stringValue(row.attention_level))).length,
|
||||
blocked_count: rows.filter((row) => stringValue(row.policy_result) === 'blocked').length,
|
||||
approval_required_count: rows.filter((row) => stringValue(row.policy_result) === 'approval_required').length,
|
||||
@@ -6558,7 +6570,10 @@ function buildGovernanceCommandForRouteDecision(
|
||||
if (decision.route_kind === 'PlanExecution' && decision.intent_kind === 'schedule') {
|
||||
const scheduleId = stringValue(contextRefs.schedule_id) || stringValue(payload.schedule_id) || stringValue(payload.scheduleId);
|
||||
if (!scheduleId) return { command: null, reasonCode: 'route_action_missing_context' };
|
||||
return { command: baseCommand('run_schedule_now', { schedule_id: scheduleId }), reasonCode: 'route_action_mapped' };
|
||||
const commandKind = 'run_schedule_now';
|
||||
const policyReason = routeGovernanceActionPolicyReason(commandKind);
|
||||
if (policyReason) return { command: null, reasonCode: policyReason };
|
||||
return { command: baseCommand(commandKind, { schedule_id: scheduleId }), reasonCode: 'route_action_mapped' };
|
||||
}
|
||||
|
||||
if (decision.route_kind === 'PlanExecution' && decision.intent_kind === 'execute') {
|
||||
@@ -6566,8 +6581,11 @@ function buildGovernanceCommandForRouteDecision(
|
||||
const taskId = stringValue(contextRefs.task_id) || stringValue(payload.task_id) || stringValue(payload.taskId) || taskIdForRouteStep(snapshot, stepId);
|
||||
if (!taskId) return { command: null, reasonCode: 'route_action_missing_context' };
|
||||
const task = runtimeTasks(snapshot).find((candidate) => candidate.id === taskId) ?? null;
|
||||
const commandKind = 'start_run';
|
||||
const policyReason = routeGovernanceActionPolicyReason(commandKind);
|
||||
if (policyReason) return { command: null, reasonCode: policyReason };
|
||||
return {
|
||||
command: baseCommand('start_run', {
|
||||
command: baseCommand(commandKind, {
|
||||
plan_id: stringValue(contextRefs.plan_id) || task?.planId || stringValue(payload.plan_id) || stringValue(payload.planId),
|
||||
task_id: taskId,
|
||||
step_id: stepId || (task ? taskStepId(task) : ''),
|
||||
@@ -6583,6 +6601,8 @@ function buildGovernanceCommandForRouteDecision(
|
||||
const planId = stringValue(contextRefs.plan_id) || stringValue(payload.plan_id) || stringValue(payload.planId);
|
||||
const commandKind = routeControlCommandKind(actionText, Boolean(taskId));
|
||||
if (!commandKind || (!taskId && !planId)) return { command: null, reasonCode: 'route_action_missing_context' };
|
||||
const policyReason = routeGovernanceActionPolicyReason(commandKind);
|
||||
if (policyReason) return { command: null, reasonCode: policyReason };
|
||||
return {
|
||||
command: baseCommand(commandKind, {
|
||||
plan_id: planId,
|
||||
@@ -6777,6 +6797,32 @@ function compactRecord(record: Record<string, unknown>): Record<string, unknown>
|
||||
return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined && value !== null && value !== ''));
|
||||
}
|
||||
|
||||
const ROUTE_LOW_RISK_GOVERNANCE_COMMANDS = new Set<GovernanceCommandRequest['command_kind']>([
|
||||
'submit_plan',
|
||||
'approve_plan',
|
||||
'amend_plan',
|
||||
'resume_plan',
|
||||
'pause_plan',
|
||||
'retry_task',
|
||||
'skip_task',
|
||||
'resume_task',
|
||||
'provide_task_input',
|
||||
]);
|
||||
const ROUTE_RISK_PROTECTED_GOVERNANCE_COMMANDS = new Set<GovernanceCommandRequest['command_kind']>([
|
||||
'activate_plan',
|
||||
'run_schedule_now',
|
||||
'start_run',
|
||||
'cancel_run',
|
||||
'cancel_task',
|
||||
'delete_schedule',
|
||||
]);
|
||||
|
||||
function routeGovernanceActionPolicyReason(commandKind: GovernanceCommandRequest['command_kind']): string | null {
|
||||
if (ROUTE_LOW_RISK_GOVERNANCE_COMMANDS.has(commandKind)) return null;
|
||||
if (ROUTE_RISK_PROTECTED_GOVERNANCE_COMMANDS.has(commandKind)) return null;
|
||||
return 'route_action_policy_blocked';
|
||||
}
|
||||
|
||||
function governanceCommandRiskLevel(commandKind: string): string {
|
||||
if (['activate_plan', 'run_schedule_now', 'start_run', 'cancel_run', 'cancel_task'].includes(commandKind)) return 'high';
|
||||
if (['delete_schedule', 'pause_schedule', 'skip_task', 'retry_task', 'provide_task_input'].includes(commandKind)) return 'medium';
|
||||
|
||||
Reference in New Issue
Block a user