feat(compliance): add content compliance detection across tenant, ops, and clients

Implements the Revision 8/9 compliance design: tenant + ops backends, ops-web
content-safety pages, admin-web editor/publish gate integration, desktop publish
block surfacing, and supporting migrations / shared types / config plumbing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 20:48:14 +08:00
parent 81577b6154
commit 745cdd79cf
73 changed files with 12747 additions and 1892 deletions
+122
View File
@@ -210,6 +210,10 @@ export interface DesktopTaskInfo {
kind: 'publish' | 'monitor'
payload: Record<string, JsonValue> | null
status: 'queued' | 'in_progress' | 'succeeded' | 'failed' | 'unknown' | 'aborted'
publish_job_status?: 'queued' | 'blocked_by_compliance' | string | null
compliance_blocked_record_id?: number | null
compliance_blocked_at?: string | null
compliance_blocked_reason?: string | null
dedup_key: string | null
active_attempt_id: string | null
lease_expires_at: string | null
@@ -324,6 +328,8 @@ export interface CreatePublishJobRequest {
content_ref: Record<string, JsonValue>
accounts: CreatePublishJobAccountRequest[]
scheduled_at?: string | null
article_version_id?: number
ack_record_id?: number
}
export interface CreatePublishJobResponse {
@@ -580,6 +586,7 @@ export interface ArticleDetail {
id: number
source_type: string
template_id: number | null
current_version_id: number | null
template_name: string | null
generation_mode: string | null
auto_publish_platforms: string[]
@@ -600,6 +607,121 @@ export interface ArticleDetail {
created_at: string
}
export type GateDecisionLiteral = 'pass' | 'block' | 'needs_ack'
export type ManualReviewStatus = 'none' | 'pending' | 'approved' | 'rejected' | 'cancelled'
export interface ComplianceRuntimeStatus {
enabled: boolean
config_enabled: boolean
master_enabled: boolean
enforcement_mode: 'mandatory' | 'advisory' | 'disabled'
llm_judge_enabled: boolean
snapshot_reload_interval: string
publish_gate_timeout: string
dictionary_version: number
enabled_dictionaries: string[]
}
export interface ComplianceViolation {
id: number
record_id?: number
platform_code?: string | null
source: 'dict' | 'regex' | 'llm'
dictionary_code?: string | null
dictionary_name?: string | null
term_pattern?: string | null
matched_text: string
start_offset: number
end_offset: number
dom_path?: string | null
level: 'block' | 'high' | 'medium' | 'info'
hint?: string | null
reference_law?: string | null
}
export interface ComplianceCheckResult {
record_id?: number
decision: GateDecisionLiteral
passed: boolean
highest_level?: string | null
violations: ComplianceViolation[]
hit_count: number
stored_hit_count: number
truncated: boolean
enforcement_mode: 'mandatory' | 'advisory' | 'disabled'
content_hash: string
policy_fingerprint: string
target_platforms: string[]
manual_review_status: ManualReviewStatus
manual_review_id?: number | null
manual_review_reason?: string | null
manual_review_decided_at?: string | null
checked_at: string
duration_ms: number
}
export interface ComplianceCheckArticleRequest {
article_version_id?: number | null
title?: string | null
plaintext?: string | null
target_platforms?: string[]
trigger_source?: 'editor_manual' | 'publish_gate'
}
export interface ComplianceCheckPlainRequest {
title?: string | null
plaintext: string
target_platforms?: string[]
}
export interface CreateAckRequest {
acknowledged_violation_ids: number[]
}
export interface ComplianceAckRecord {
id: number
check_record_id: number
article_id: number
article_version_id: number
content_hash: string
policy_fingerprint: string
expires_at: string
created_at: string
}
export interface ComplianceManualReview {
id: number
tenant_id: number
article_id: number
article_version_id: number
check_record_id?: number | null
status: ManualReviewStatus
requested_by: number
requested_at: string
request_note?: string | null
reviewed_by?: number | null
reviewed_at?: string | null
decision_reason?: string | null
cancelled_by?: number | null
cancelled_at?: string | null
cancel_reason?: string | null
violation_summary: ComplianceViolation[]
original_target_platforms: string[]
article_title?: string | null
article_plaintext?: string | null
applicant_name?: string | null
tenant_name?: string | null
}
export interface CreateManualReviewRequest {
check_record_id: number
note: string
}
export interface CancelManualReviewRequest {
reason?: string | null
}
export interface CreateArticleRequest {
title?: string
}