feat(governance): 新增 AI Agent TG canary 批准包
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
CD Pipeline / tests (push) Successful in 1m46s
CD Pipeline / build-and-deploy (push) Successful in 6m39s
CD Pipeline / post-deploy-checks (push) Successful in 2m53s

This commit is contained in:
Your Name
2026-06-16 10:14:23 +08:00
parent 915cbaac0c
commit 44ea892e4f
14 changed files with 2110 additions and 43 deletions

View File

@@ -3711,6 +3711,17 @@ export function AutomationInventoryTab() {
+ professionalTaskExpansion.rollups.preview_bot_api_call_enabled_count
+ professionalTaskExpansion.rollups.receipt_live_write_enabled_count
+ professionalTaskExpansion.rollups.canary_live_send_enabled_count
+ professionalTaskExpansion.rollups.canary_send_execution_enabled_count
+ professionalTaskExpansion.rollups.canary_gateway_queue_write_enabled_count
+ professionalTaskExpansion.rollups.canary_bot_api_call_enabled_count
+ professionalTaskExpansion.rollups.canary_delivery_receipt_write_enabled_count
+ professionalTaskExpansion.rollups.canary_secret_read_enabled_count
)
const professionalTaskCanarySendPacket = professionalTaskExpansion.telegram_runtime_bridge.canary_send_approval_packet
const professionalTaskCanaryApprovalGaps = (
professionalTaskExpansion.rollups.canary_approval_granted_count
+ professionalTaskExpansion.rollups.canary_selected_message_type_count
+ professionalTaskExpansion.rollups.canary_approved_time_window_count
)
const backlogProgressPercent = backlog.progress_summary.overall_percent
const explicitApprovalItemCount = backlog.item_approval_boundary_rollup.items_requiring_explicit_approval.length
@@ -4137,6 +4148,10 @@ export function AutomationInventoryTab() {
<MetricCard label={t('professionalTaskExpansion.metrics.dedupKeys')} value={professionalTaskExpansion.rollups.dedup_key_count} tone="ok" icon={<Fingerprint size={16} />} />
<MetricCard label={t('professionalTaskExpansion.metrics.receipts')} value={professionalTaskExpansion.rollups.receipt_expectation_count} tone="warn" icon={<ClipboardCheck size={16} />} />
<MetricCard label={t('professionalTaskExpansion.metrics.previewLiveWrites')} value={professionalTaskPreviewLiveWrites} tone={professionalTaskPreviewLiveWrites === 0 ? 'ok' : 'danger'} icon={<BellOff size={16} />} />
<MetricCard label={t('professionalTaskExpansion.metrics.canaryPacket')} value={professionalTaskExpansion.rollups.canary_send_approval_packet_count} tone="warn" icon={<ClipboardCheck size={16} />} />
<MetricCard label={t('professionalTaskExpansion.metrics.canaryFields')} value={professionalTaskExpansion.rollups.canary_operator_approval_field_count} tone="warn" icon={<FileText size={16} />} />
<MetricCard label={t('professionalTaskExpansion.metrics.stopConditions')} value={professionalTaskExpansion.rollups.canary_stop_condition_count} tone="danger" icon={<ShieldAlert size={16} />} />
<MetricCard label={t('professionalTaskExpansion.metrics.canaryApprovalGaps')} value={professionalTaskCanaryApprovalGaps} tone={professionalTaskCanaryApprovalGaps === 0 ? 'ok' : 'danger'} icon={<BellOff size={16} />} />
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 10 }}>
@@ -4223,6 +4238,44 @@ export function AutomationInventoryTab() {
</div>
</div>
<div style={{ padding: 10, border: '0.5px solid #d7c7a1', borderRadius: 7, background: '#fff', minWidth: 0 }}>
<SmallLabel>{t('professionalTaskExpansion.canarySendPacketTitle')}</SmallLabel>
<p style={{ margin: '6px 0 8px', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.5, color: '#5c5a55', overflowWrap: 'anywhere' }}>
{professionalTaskCanarySendPacket.packet_id} · {professionalTaskCanarySendPacket.status}
</p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 8 }}>
<Chip value={t('professionalTaskExpansion.labels.packetReady', { value: String(professionalTaskCanarySendPacket.packet_ready) })} />
<Chip value={t('professionalTaskExpansion.labels.approvalGranted', { value: String(professionalTaskCanarySendPacket.approval_granted) })} muted />
<Chip value={t('professionalTaskExpansion.labels.recommendedMessage', { value: professionalTaskCanarySendPacket.recommended_first_message_type })} muted />
<Chip value={t('professionalTaskExpansion.labels.selectedMessage', { value: professionalTaskCanarySendPacket.selected_message_type })} muted />
<Chip value={t('professionalTaskExpansion.labels.timeWindow', { value: professionalTaskCanarySendPacket.proposed_time_window })} muted />
<Chip value={t('professionalTaskExpansion.labels.canarySend', { value: String(professionalTaskCanarySendPacket.execution_flags.canary_send_execution_enabled) })} muted />
<Chip value={t('professionalTaskExpansion.labels.queueWrites', { value: String(professionalTaskCanarySendPacket.execution_flags.gateway_queue_write_enabled) })} muted />
<Chip value={t('professionalTaskExpansion.labels.botCalls', { value: String(professionalTaskCanarySendPacket.execution_flags.bot_api_call_enabled) })} muted />
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 8 }}>
{professionalTaskCanarySendPacket.operator_approval_fields.map(field => (
<div key={field.field_id} style={{ padding: 8, borderRadius: 6, background: '#f8f5ed', display: 'flex', flexDirection: 'column', gap: 5, minWidth: 0 }}>
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 11, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
{field.label}
</span>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
<Chip value={t('professionalTaskExpansion.labels.required', { value: String(field.required) })} muted />
<Chip value={t('professionalTaskExpansion.labels.inputStatus', { value: field.current_value_status })} muted />
<Chip value={t('professionalTaskExpansion.labels.valueVisible', { value: String(field.value_display_allowed) })} muted />
</div>
</div>
))}
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 8, marginTop: 8 }}>
{professionalTaskCanarySendPacket.stop_conditions.slice(0, 6).map(condition => (
<div key={condition} style={{ padding: 8, borderRadius: 6, background: '#fff7ed', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.45, color: '#7a4a20', overflowWrap: 'anywhere' }}>
{condition}
</div>
))}
</div>
</div>
<SmallLabel>{t('professionalTaskExpansion.tasksTitle')}</SmallLabel>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
{visibleProfessionalTasks.map(task => {

View File

@@ -1429,8 +1429,8 @@ export interface AiAgentProfessionalTaskExpansionSnapshot {
program_status: {
overall_completion_percent: number
current_priority: 'P0' | 'P1' | 'P2' | 'P3'
current_task_id: 'P2-405B'
next_task_id: 'P2-405C'
current_task_id: 'P2-405C'
next_task_id: 'P2-405D'
read_only_mode: true
runtime_authority: 'professional_task_expansion_and_telegram_bridge_read_only_no_send'
status_note: string
@@ -1539,8 +1539,61 @@ export interface AiAgentProfessionalTaskExpansionSnapshot {
delivery_receipt_write_enabled: boolean
production_write_enabled: boolean
}
canary_send_approval_packet: {
packet_id: string
status: string
packet_ready: boolean
approval_required: boolean
approval_granted: boolean
recommended_first_message_type: string
selected_message_type: string
eligible_message_types: string[]
target_room_alias: string
target_room_env: string
target_room_value_visible: boolean
proposed_time_window: string
owner_agent: string
arbiter: string
reviewers: string[]
operator_approval_fields: Array<{
field_id: string
label: string
required: boolean
current_value_status: string
value_display_allowed: boolean
}>
rate_limit_plan: {
max_messages: number
window: string
cooldown_after_attempt_minutes: number
duplicate_policy: string
live_rate_limit_write_enabled: boolean
}
mute_rollback_plan: string[]
receipt_readback_plan: {
owner_agent: string
required_checks: string[]
production_receipt_write_enabled: boolean
receipt_readback_enabled_before_send: boolean
}
stop_conditions: string[]
execution_flags: {
canary_send_execution_enabled: boolean
gateway_queue_write_enabled: boolean
bot_api_call_enabled: boolean
delivery_receipt_write_enabled: boolean
production_write_enabled: boolean
secret_read_enabled: boolean
paid_api_enabled: boolean
}
approval_decision_log: unknown[]
}
no_send_preview_completion_percent: number
canary_approval_package_completion_percent: number
canary_send_approval_packet_ready: boolean
canary_send_approval_granted: boolean
canary_send_execution_enabled: boolean
canary_send_approval_packet_completion_percent: number
}
professional_task_domains: Array<{
domain_id: string
@@ -1576,6 +1629,7 @@ export interface AiAgentProfessionalTaskExpansionSnapshot {
telegram_message_must_be_sanitized: boolean
frontend_display_policy: string
message_preview_redaction_checks: string[]
canary_packet_redaction_checks: string[]
}
rollups: {
professional_task_count: number
@@ -1609,6 +1663,19 @@ export interface AiAgentProfessionalTaskExpansionSnapshot {
preview_bot_api_call_enabled_count: number
receipt_live_write_enabled_count: number
canary_live_send_enabled_count: number
canary_send_approval_packet_count: number
canary_operator_approval_field_count: number
canary_stop_condition_count: number
canary_rollback_mute_step_count: number
canary_receipt_readback_check_count: number
canary_approval_granted_count: number
canary_selected_message_type_count: number
canary_approved_time_window_count: number
canary_send_execution_enabled_count: number
canary_gateway_queue_write_enabled_count: number
canary_bot_api_call_enabled_count: number
canary_delivery_receipt_write_enabled_count: number
canary_secret_read_enabled_count: number
}
}