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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user