feat: govern knowledge assets and source citations

This commit is contained in:
key
2026-08-02 01:43:43 +08:00
parent cafb836cda
commit 699cc08050
144 changed files with 17205 additions and 453 deletions
@@ -27,7 +27,10 @@ CREATE TABLE IF NOT EXISTS `aihr_knowledge_answer_feedback` (
`position` varchar(80) DEFAULT NULL COMMENT '岗位',
`source` varchar(50) DEFAULT 'knowledge_search' COMMENT '来源',
`review_id` bigint DEFAULT NULL COMMENT '对应SOP问答评审ID',
`request_id` varchar(64) DEFAULT NULL COMMENT '知识查询请求ID',
`review_status` varchar(30) DEFAULT '待复核' COMMENT '复核状态',
`review_action` varchar(20) DEFAULT NULL COMMENT '复核动作 KEEP/WITHDRAW',
`review_note` varchar(500) DEFAULT NULL COMMENT '复核结论',
`reviewer` varchar(100) DEFAULT NULL COMMENT '复核人',
`reviewed_time` datetime DEFAULT NULL COMMENT '复核时间',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
@@ -56,5 +56,54 @@ PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEA
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_points_ledger` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
-- Data-quality lifecycle tables are introduced after the original release
-- migration but participate in tenant-scoped joins with legacy knowledge tables.
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_data_asset` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_data_version` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_quality_assessment` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_quality_issue` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_review_decision` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_chunk_revision` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_lineage_edge` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_index_outbox` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_query_evidence` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_dataset_membership` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_duplicate_relation` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_knowledge_claim` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_claim_conflict` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_quality_alert` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_processing_rule` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_processing_rule_transition` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_rule_evaluation` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_review_sample` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_pipeline_run` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_golden_dataset` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_golden_sample` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_rule_golden_evaluation` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := CONCAT('ALTER TABLE `aihr_rule_acceptance_profile` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_release_collation);
PREPARE aihr_release_stmt FROM @aihr_release_ddl; EXECUTE aihr_release_stmt; DEALLOCATE PREPARE aihr_release_stmt;
SET @aihr_release_ddl := NULL;
SET @aihr_release_collation := NULL;
@@ -0,0 +1,43 @@
-- Citation source locations. This table is intentionally a sidecar to the
-- retrieval fragment table so old fragments and queries remain compatible.
CREATE TABLE IF NOT EXISTS `aihr_knowledge_fragment_locator` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`fragment_id` bigint NOT NULL,
`knowledge_id` bigint NOT NULL,
`doc_id` varchar(80) DEFAULT NULL,
`attachment_id` bigint DEFAULT NULL,
`source_kind` varchar(12) NOT NULL,
`page_number` int DEFAULT NULL,
`slide_number` int DEFAULT NULL,
`paragraph_start` int DEFAULT NULL,
`paragraph_end` int DEFAULT NULL,
`sheet_name` varchar(255) DEFAULT NULL,
`row_start` int DEFAULT NULL,
`row_end` int DEFAULT NULL,
`start_ms` bigint DEFAULT NULL,
`end_ms` bigint DEFAULT NULL,
`frame_ms` bigint DEFAULT NULL,
`locator_version` varchar(32) NOT NULL DEFAULT 'v1',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_fragment_locator_fragment` (`tenant_id`, `fragment_id`),
KEY `idx_aihr_fragment_locator_attachment` (`tenant_id`, `attachment_id`, `source_kind`),
CONSTRAINT `ck_aihr_fragment_locator_kind` CHECK (`source_kind` in ('TEXT','PDF','DOCX','PPTX','XLSX','IMAGE','VIDEO')),
CONSTRAINT `ck_aihr_fragment_locator_nonnegative` CHECK (
(`page_number` is null or `page_number` >= 0) and
(`slide_number` is null or `slide_number` >= 0) and
(`paragraph_start` is null or `paragraph_start` >= 0) and
(`paragraph_end` is null or `paragraph_end` >= 0) and
(`row_start` is null or `row_start` >= 0) and
(`row_end` is null or `row_end` >= 0) and
(`start_ms` is null or `start_ms` >= 0) and
(`end_ms` is null or `end_ms` >= 0) and
(`frame_ms` is null or `frame_ms` >= 0)
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Knowledge fragment source location sidecar';
-- Safe on repeat runs and fixes databases created from the pre-release draft.
ALTER TABLE `aihr_knowledge_fragment_locator`
MODIFY COLUMN `tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;
@@ -0,0 +1,225 @@
-- Knowledge data-quality lifecycle. Additive and safe to run repeatedly on MySQL 8.
-- Raw objects remain in MinIO/sys_oss; parsed and normalized versions are immutable rows.
CREATE TABLE IF NOT EXISTS `aihr_data_asset` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`knowledge_id` bigint NOT NULL,
`attachment_id` bigint DEFAULT NULL,
`doc_id` varchar(80) NOT NULL,
`raw_oss_id` bigint DEFAULT NULL,
`source_type` varchar(30) NOT NULL,
`source_name` varchar(500) NOT NULL,
`source_authority` varchar(30) NOT NULL DEFAULT 'UNKNOWN',
`source_version` varchar(100) DEFAULT NULL,
`data_class` varchar(40) NOT NULL DEFAULT 'REFERENCE_ONLY',
`trust_level` varchar(30) NOT NULL DEFAULT 'UNTRUSTED',
`lifecycle_status` varchar(30) NOT NULL DEFAULT 'RAW',
`index_status` varchar(20) NOT NULL DEFAULT 'NOT_REQUIRED',
`content_sha256` char(64) DEFAULT NULL,
`applicable_region` varchar(100) DEFAULT NULL,
`applicable_project` varchar(100) DEFAULT NULL,
`applicable_role` varchar(100) DEFAULT NULL,
`effective_from` date DEFAULT NULL,
`effective_to` date DEFAULT NULL,
`supersedes_asset_id` bigint DEFAULT NULL,
`near_duplicate_cluster_id` bigint DEFAULT NULL,
`current_version_id` bigint DEFAULT NULL,
`created_by` bigint DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_data_asset_doc` (`tenant_id`, `knowledge_id`, `doc_id`),
KEY `idx_aihr_data_asset_review` (`tenant_id`, `lifecycle_status`, `update_time`),
KEY `idx_aihr_data_asset_attachment` (`tenant_id`, `attachment_id`),
KEY `idx_aihr_data_asset_effective` (`tenant_id`, `effective_from`, `effective_to`),
KEY `idx_aihr_data_asset_near_duplicate` (`tenant_id`, `near_duplicate_cluster_id`),
CONSTRAINT `ck_aihr_data_asset_lifecycle` CHECK (`lifecycle_status` IN
('RAW','PARSED','NORMALIZED','CLASSIFIED','DEDUPLICATED','PRIVACY_CHECKED','DOMAIN_VALIDATED',
'QUALITY_EVALUATED','QUARANTINED','REVIEW_PENDING','APPROVED','PUBLISHED','DEPRECATED')),
CONSTRAINT `ck_aihr_data_asset_index` CHECK (`index_status` IN ('NOT_REQUIRED','PENDING','READY','FAILED'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Governed knowledge data asset';
CREATE TABLE IF NOT EXISTS `aihr_data_version` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`asset_id` bigint NOT NULL,
`version_no` int NOT NULL,
`parsed_content` longtext DEFAULT NULL,
`normalized_content` longtext DEFAULT NULL,
`content_sha256` char(64) NOT NULL,
`parser_name` varchar(100) NOT NULL,
`parser_version` varchar(50) NOT NULL,
`cleaning_policy_version` varchar(50) NOT NULL,
`classification_policy_version` varchar(50) NOT NULL,
`simhash64` char(16) DEFAULT NULL,
`structure_profile_json` json DEFAULT NULL,
`extractor_name` varchar(100) DEFAULT NULL,
`extractor_version` varchar(50) DEFAULT NULL,
`extraction_quality_json` json DEFAULT NULL,
`expected_page_count` int DEFAULT NULL,
`extracted_page_count` int DEFAULT NULL,
`min_ocr_confidence` decimal(6,5) DEFAULT NULL,
`ocr_used` tinyint(1) NOT NULL DEFAULT 0,
`synthetic` tinyint(1) NOT NULL DEFAULT 0,
`immutable_status` varchar(20) NOT NULL DEFAULT 'SEALED',
`created_by` bigint DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_data_version_no` (`tenant_id`, `asset_id`, `version_no`),
KEY `idx_aihr_data_version_hash` (`tenant_id`, `content_sha256`),
KEY `idx_aihr_data_version_simhash` (`tenant_id`, `simhash64`),
CONSTRAINT `ck_aihr_data_version_immutable` CHECK (`immutable_status` = 'SEALED')
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Immutable parsed and normalized asset version';
CREATE TABLE IF NOT EXISTS `aihr_quality_assessment` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`asset_id` bigint NOT NULL,
`version_id` bigint NOT NULL,
`policy_version` varchar(50) NOT NULL,
`gate_result` varchar(20) NOT NULL,
`dimensions_json` json DEFAULT NULL,
`detector_summary_json` json DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_aihr_quality_assessment_version` (`tenant_id`, `version_id`, `create_time`),
CONSTRAINT `ck_aihr_quality_gate_result` CHECK (`gate_result` IN ('PASS','REVIEW','BLOCK'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Versioned multi-dimensional quality assessment';
CREATE TABLE IF NOT EXISTS `aihr_quality_issue` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`asset_id` bigint NOT NULL,
`version_id` bigint NOT NULL,
`assessment_id` bigint DEFAULT NULL,
`origin_feedback_id` bigint DEFAULT NULL,
`reason_code` varchar(64) NOT NULL,
`severity` varchar(20) NOT NULL,
`gate_type` varchar(20) NOT NULL,
`evidence_json` json DEFAULT NULL,
`recommended_action` varchar(500) DEFAULT NULL,
`detector_type` varchar(20) NOT NULL,
`detector_version` varchar(50) NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'OPEN',
`resolved_by` bigint DEFAULT NULL,
`resolved_time` datetime DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_aihr_quality_issue_open` (`tenant_id`, `asset_id`, `status`, `severity`),
KEY `idx_aihr_quality_issue_reason` (`tenant_id`, `reason_code`, `create_time`),
UNIQUE KEY `uk_aihr_quality_issue_feedback` (`tenant_id`, `origin_feedback_id`, `reason_code`),
CONSTRAINT `ck_aihr_quality_issue_severity` CHECK (`severity` IN ('INFO','WARNING','ERROR','CRITICAL')),
CONSTRAINT `ck_aihr_quality_issue_gate` CHECK (`gate_type` IN ('HARD','SOFT')),
CONSTRAINT `ck_aihr_quality_issue_status` CHECK (`status` IN ('OPEN','ACCEPTED','RESOLVED','FALSE_POSITIVE'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Explainable quality findings and reason codes';
CREATE TABLE IF NOT EXISTS `aihr_review_decision` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`asset_id` bigint NOT NULL,
`version_id` bigint NOT NULL,
`decision` varchar(20) NOT NULL,
`reason` varchar(1000) NOT NULL,
`before_snapshot_json` json DEFAULT NULL,
`after_snapshot_json` json DEFAULT NULL,
`reviewer_id` bigint NOT NULL,
`reviewer_type` varchar(20) NOT NULL DEFAULT 'HUMAN',
`reviewed_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_aihr_review_asset` (`tenant_id`, `asset_id`, `reviewed_time`),
CONSTRAINT `ck_aihr_review_decision` CHECK (`decision` IN ('APPROVE','REJECT','QUARANTINE','WITHDRAW','DEPRECATE')),
CONSTRAINT `ck_aihr_review_human` CHECK (`reviewer_type` = 'HUMAN')
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Human review decisions';
CREATE TABLE IF NOT EXISTS `aihr_chunk_revision` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`asset_id` bigint NOT NULL,
`version_id` bigint NOT NULL,
`chunk_index` int NOT NULL,
`content` text NOT NULL,
`content_sha256` char(64) NOT NULL,
`heading_path` varchar(1000) DEFAULT NULL,
`context_prefix` varchar(500) DEFAULT NULL,
`locator_json` json DEFAULT NULL,
`chunker_version` varchar(50) NOT NULL,
`published_fragment_id` bigint DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_chunk_revision_index` (`tenant_id`, `version_id`, `chunk_index`),
KEY `idx_aihr_chunk_revision_asset` (`tenant_id`, `asset_id`, `version_id`),
KEY `idx_aihr_chunk_revision_fragment` (`tenant_id`, `published_fragment_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Immutable candidate and published chunk revisions';
CREATE TABLE IF NOT EXISTS `aihr_lineage_edge` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`from_type` varchar(30) NOT NULL,
`from_id` varchar(100) NOT NULL,
`to_type` varchar(30) NOT NULL,
`to_id` varchar(100) NOT NULL,
`relation_type` varchar(30) NOT NULL,
`processor_name` varchar(100) DEFAULT NULL,
`processor_version` varchar(50) DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_lineage_edge` (`tenant_id`, `from_type`, `from_id`, `to_type`, `to_id`, `relation_type`),
KEY `idx_aihr_lineage_reverse` (`tenant_id`, `to_type`, `to_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Data lineage between raw objects versions chunks and fragments';
CREATE TABLE IF NOT EXISTS `aihr_index_outbox` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`asset_id` bigint NOT NULL,
`version_id` bigint NOT NULL,
`operation` varchar(20) NOT NULL,
`target_collection` varchar(100) NOT NULL,
`payload_json` json DEFAULT NULL,
`status` varchar(20) NOT NULL DEFAULT 'PENDING',
`attempt_count` int NOT NULL DEFAULT 0,
`next_attempt_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_error` varchar(1000) DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_aihr_index_outbox_claim` (`status`, `next_attempt_time`, `id`),
KEY `idx_aihr_index_outbox_asset` (`tenant_id`, `asset_id`, `id`),
CONSTRAINT `ck_aihr_index_outbox_operation` CHECK (`operation` IN ('UPSERT','DELETE')),
CONSTRAINT `ck_aihr_index_outbox_status` CHECK (`status` IN ('PENDING','PROCESSING','SUCCEEDED','FAILED','DEAD_LETTER'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Durable vector-index operations';
CREATE TABLE IF NOT EXISTS `aihr_query_evidence` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`request_id` varchar(64) NOT NULL,
`rank_no` int NOT NULL,
`fragment_id` bigint NOT NULL,
`chunk_revision_id` bigint DEFAULT NULL,
`asset_id` bigint DEFAULT NULL,
`version_id` bigint DEFAULT NULL,
`retrieval_channel` varchar(20) NOT NULL,
`retrieval_score` decimal(12,8) DEFAULT NULL,
`used_in_answer` tinyint(1) NOT NULL DEFAULT 0,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_query_evidence_rank` (`tenant_id`, `request_id`, `rank_no`),
KEY `idx_aihr_query_evidence_fragment` (`tenant_id`, `fragment_id`, `create_time`),
KEY `idx_aihr_query_evidence_asset` (`tenant_id`, `asset_id`, `version_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Per-query retrieval and answer evidence';
CREATE TABLE IF NOT EXISTS `aihr_dataset_membership` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`version_id` bigint NOT NULL,
`dataset_code` varchar(50) NOT NULL,
`usage_type` varchar(40) NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'ACTIVE',
`approved_review_id` bigint DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_dataset_membership` (`tenant_id`, `version_id`, `dataset_code`),
KEY `idx_aihr_dataset_usage` (`tenant_id`, `dataset_code`, `usage_type`, `status`),
CONSTRAINT `ck_aihr_dataset_usage` CHECK (`usage_type` IN
('NORMATIVE_KNOWLEDGE','POSITIVE_CASE','NEGATIVE_CASE','ROLEPLAY_MATERIAL','ASSESSMENT_ITEM','REFERENCE_ONLY','UNUSABLE'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Explicit routing to production case training and evaluation datasets';
@@ -0,0 +1,26 @@
-- Add a terminal outbox state so repeated Qdrant failures are visible and do not retry forever.
-- Idempotent on MySQL 8: replace the named check constraint with the current definition.
SET @aihr_outbox_check_exists := (
SELECT COUNT(*)
FROM information_schema.table_constraints
WHERE table_schema = DATABASE()
AND table_name = 'aihr_index_outbox'
AND constraint_name = 'ck_aihr_index_outbox_status'
AND constraint_type = 'CHECK'
);
SET @aihr_outbox_ddl := IF(
@aihr_outbox_check_exists > 0,
'ALTER TABLE `aihr_index_outbox` DROP CHECK `ck_aihr_index_outbox_status`',
'SELECT 1'
);
PREPARE aihr_outbox_stmt FROM @aihr_outbox_ddl;
EXECUTE aihr_outbox_stmt;
DEALLOCATE PREPARE aihr_outbox_stmt;
ALTER TABLE `aihr_index_outbox`
ADD CONSTRAINT `ck_aihr_index_outbox_status`
CHECK (`status` IN ('PENDING','PROCESSING','SUCCEEDED','FAILED','DEAD_LETTER'));
SET @aihr_outbox_check_exists := NULL;
SET @aihr_outbox_ddl := NULL;
@@ -0,0 +1,86 @@
-- Structure-aware processing and near-duplicate candidate metadata.
-- Additive and idempotent on MySQL 8. Existing immutable versions are not rewritten.
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_asset'
AND column_name = 'near_duplicate_cluster_id'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_data_asset` ADD COLUMN `near_duplicate_cluster_id` bigint DEFAULT NULL AFTER `supersedes_asset_id`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_asset'
AND index_name = 'idx_aihr_data_asset_near_duplicate'
);
SET @aihr_ddl := IF(@aihr_index_exists = 0,
'ALTER TABLE `aihr_data_asset` ADD KEY `idx_aihr_data_asset_near_duplicate` (`tenant_id`, `near_duplicate_cluster_id`)',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version' AND column_name = 'simhash64'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_data_version` ADD COLUMN `simhash64` char(16) DEFAULT NULL AFTER `classification_policy_version`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version' AND column_name = 'structure_profile_json'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_data_version` ADD COLUMN `structure_profile_json` json DEFAULT NULL AFTER `simhash64`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version' AND column_name = 'extractor_name'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_data_version` ADD COLUMN `extractor_name` varchar(100) DEFAULT NULL AFTER `structure_profile_json`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version' AND column_name = 'extractor_version'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_data_version` ADD COLUMN `extractor_version` varchar(50) DEFAULT NULL AFTER `extractor_name`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND index_name = 'idx_aihr_data_version_simhash'
);
SET @aihr_ddl := IF(@aihr_index_exists = 0,
'ALTER TABLE `aihr_data_version` ADD KEY `idx_aihr_data_version_simhash` (`tenant_id`, `simhash64`)',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := NULL;
SET @aihr_index_exists := NULL;
SET @aihr_ddl := NULL;
@@ -0,0 +1,66 @@
-- Bind runtime answer disputes to retrieval evidence and governed source versions.
-- Additive and idempotent; no historical feedback is auto-promoted or auto-withdrawn.
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_answer_feedback'
AND column_name = 'request_id'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_knowledge_answer_feedback` ADD COLUMN `request_id` varchar(64) DEFAULT NULL AFTER `review_id`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_answer_feedback'
AND column_name = 'review_action'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_knowledge_answer_feedback` ADD COLUMN `review_action` varchar(20) DEFAULT NULL AFTER `review_status`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_answer_feedback'
AND column_name = 'review_note'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_knowledge_answer_feedback` ADD COLUMN `review_note` varchar(500) DEFAULT NULL AFTER `review_action`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := (
SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_quality_issue'
AND column_name = 'origin_feedback_id'
);
SET @aihr_ddl := IF(@aihr_column_exists = 0,
'ALTER TABLE `aihr_quality_issue` ADD COLUMN `origin_feedback_id` bigint DEFAULT NULL AFTER `assessment_id`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_quality_issue'
AND index_name = 'uk_aihr_quality_issue_feedback'
);
SET @aihr_ddl := IF(@aihr_index_exists = 0,
'ALTER TABLE `aihr_quality_issue` ADD UNIQUE KEY `uk_aihr_quality_issue_feedback` (`tenant_id`, `origin_feedback_id`, `reason_code`)',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_column_exists := NULL;
SET @aihr_index_exists := NULL;
SET @aihr_ddl := NULL;
@@ -0,0 +1,42 @@
-- Preserve every uploaded attachment identity, including same-name and exact-duplicate uploads.
-- Raw OSS objects may be referenced by more than one attachment, but an existing attachment
-- must never be repointed to a new OSS object merely because the display name matches.
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_attach'
AND index_name = 'uk_aihr_knowledge_attach_name'
);
SET @aihr_ddl := IF(@aihr_index_exists > 0,
'ALTER TABLE `aihr_knowledge_attach` DROP INDEX `uk_aihr_knowledge_attach_name`',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_attach'
AND index_name = 'idx_aihr_knowledge_attach_name'
);
SET @aihr_ddl := IF(@aihr_index_exists = 0,
'ALTER TABLE `aihr_knowledge_attach` ADD KEY `idx_aihr_knowledge_attach_name` (`tenant_id`, `knowledge_id`, `name`)',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_knowledge_attach'
AND index_name = 'uk_aihr_knowledge_attach_doc'
);
SET @aihr_ddl := IF(@aihr_index_exists = 0,
'ALTER TABLE `aihr_knowledge_attach` ADD UNIQUE KEY `uk_aihr_knowledge_attach_doc` (`tenant_id`, `knowledge_id`, `doc_id`)',
'SELECT 1');
PREPARE aihr_stmt FROM @aihr_ddl;
EXECUTE aihr_stmt;
DEALLOCATE PREPARE aihr_stmt;
SET @aihr_index_exists := NULL;
SET @aihr_ddl := NULL;
@@ -0,0 +1,57 @@
-- Preserve parser/OCR page-level evidence and make parse failures auditable.
-- Additive and safe to run repeatedly on MySQL 8.
SET @ddl := IF(
EXISTS (SELECT 1 FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version')
AND NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'extraction_quality_json'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `extraction_quality_json` json DEFAULT NULL AFTER `extractor_version`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
EXISTS (SELECT 1 FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version')
AND NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'expected_page_count'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `expected_page_count` int DEFAULT NULL AFTER `extraction_quality_json`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
EXISTS (SELECT 1 FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version')
AND NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'extracted_page_count'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `extracted_page_count` int DEFAULT NULL AFTER `expected_page_count`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
EXISTS (SELECT 1 FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version')
AND NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'min_ocr_confidence'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `min_ocr_confidence` decimal(6,5) DEFAULT NULL AFTER `extracted_page_count`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
EXISTS (SELECT 1 FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version')
AND NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'ocr_used'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `ocr_used` tinyint(1) NOT NULL DEFAULT 0 AFTER `min_ocr_confidence`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
@@ -0,0 +1,182 @@
-- Semantic duplicate candidates and claim-level conflict evidence.
-- Additive and idempotent on MySQL 8. Detectors only create review evidence;
-- they never approve, merge, supersede or delete knowledge automatically.
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_asset'
AND column_name = 'semantic_duplicate_cluster_id'),
'ALTER TABLE `aihr_data_asset` ADD COLUMN `semantic_duplicate_cluster_id` bigint DEFAULT NULL AFTER `near_duplicate_cluster_id`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_asset'
AND index_name = 'idx_aihr_data_asset_semantic_duplicate'),
'ALTER TABLE `aihr_data_asset` ADD KEY `idx_aihr_data_asset_semantic_duplicate` (`tenant_id`, `semantic_duplicate_cluster_id`)',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'semantic_analysis_status'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `semantic_analysis_status` varchar(20) NOT NULL DEFAULT ''PENDING'' AFTER `ocr_used`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.table_constraints
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND constraint_name = 'ck_aihr_data_version_semantic_status'),
'ALTER TABLE `aihr_data_version` ADD CONSTRAINT `ck_aihr_data_version_semantic_status` CHECK (`semantic_analysis_status` IN (''PENDING'',''PROCESSING'',''COMPLETE'',''NOT_REQUIRED'',''FAILED'',''DEAD_LETTER''))',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'semantic_embedding_json'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `semantic_embedding_json` json DEFAULT NULL AFTER `semantic_analysis_status`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'semantic_embedding_model'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `semantic_embedding_model` varchar(100) DEFAULT NULL AFTER `semantic_embedding_json`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'semantic_embedding_dimension'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `semantic_embedding_dimension` int DEFAULT NULL AFTER `semantic_embedding_model`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'semantic_detector_version'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `semantic_detector_version` varchar(50) DEFAULT NULL AFTER `semantic_embedding_dimension`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'semantic_retry_count'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `semantic_retry_count` int NOT NULL DEFAULT 0 AFTER `semantic_detector_version`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'semantic_next_retry_time'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `semantic_next_retry_time` datetime DEFAULT NULL AFTER `semantic_retry_count`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'semantic_last_error'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `semantic_last_error` varchar(500) DEFAULT NULL AFTER `semantic_next_retry_time`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND index_name = 'idx_aihr_data_version_semantic_queue'),
'ALTER TABLE `aihr_data_version` ADD KEY `idx_aihr_data_version_semantic_queue` (`semantic_analysis_status`, `semantic_next_retry_time`, `id`)',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
CREATE TABLE IF NOT EXISTS `aihr_duplicate_relation` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`left_asset_id` bigint NOT NULL,
`left_version_id` bigint NOT NULL,
`right_asset_id` bigint NOT NULL,
`right_version_id` bigint NOT NULL,
`relation_type` varchar(20) NOT NULL,
`similarity_score` decimal(8,6) DEFAULT NULL,
`detector_type` varchar(20) NOT NULL,
`detector_version` varchar(50) NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'PENDING_REVIEW',
`reviewed_by` bigint DEFAULT NULL,
`review_note` varchar(500) DEFAULT NULL,
`reviewed_time` datetime DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_duplicate_relation` (`tenant_id`, `left_version_id`, `right_version_id`, `relation_type`),
KEY `idx_aihr_duplicate_relation_review` (`tenant_id`, `status`, `relation_type`, `create_time`),
KEY `idx_aihr_duplicate_relation_right` (`tenant_id`, `right_asset_id`, `right_version_id`),
CONSTRAINT `ck_aihr_duplicate_relation_type` CHECK (`relation_type` IN ('EXACT','NEAR','SEMANTIC')),
CONSTRAINT `ck_aihr_duplicate_relation_status` CHECK (`status` IN ('PENDING_REVIEW','CONFIRMED','FALSE_POSITIVE','RESOLVED'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Auditable duplicate candidates; never an automatic merge decision';
CREATE TABLE IF NOT EXISTS `aihr_knowledge_claim` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`asset_id` bigint NOT NULL,
`version_id` bigint NOT NULL,
`claim_index` int NOT NULL,
`claim_key` char(64) NOT NULL,
`claim_text` varchar(2000) NOT NULL,
`normalized_value` varchar(500) DEFAULT NULL,
`polarity` varchar(20) NOT NULL DEFAULT 'NEUTRAL',
`condition_text` varchar(1000) DEFAULT NULL,
`source_authority` varchar(30) NOT NULL DEFAULT 'UNKNOWN',
`status` varchar(20) NOT NULL DEFAULT 'CANDIDATE',
`extractor_type` varchar(20) NOT NULL,
`extractor_version` varchar(50) NOT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_knowledge_claim_index` (`tenant_id`, `version_id`, `claim_index`),
KEY `idx_aihr_knowledge_claim_key` (`tenant_id`, `claim_key`, `status`),
KEY `idx_aihr_knowledge_claim_asset` (`tenant_id`, `asset_id`, `version_id`),
CONSTRAINT `ck_aihr_knowledge_claim_polarity` CHECK (`polarity` IN ('REQUIRED','PROHIBITED','ALLOWED','NEUTRAL')),
CONSTRAINT `ck_aihr_knowledge_claim_status` CHECK (`status` IN ('CANDIDATE','PUBLISHED','DEPRECATED'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Rule-extracted claims and viewpoints with source evidence';
CREATE TABLE IF NOT EXISTS `aihr_claim_conflict` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`left_claim_id` bigint NOT NULL,
`right_claim_id` bigint NOT NULL,
`conflict_type` varchar(30) NOT NULL,
`evidence_json` json NOT NULL,
`detector_version` varchar(50) NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'PENDING_REVIEW',
`reviewed_by` bigint DEFAULT NULL,
`review_note` varchar(500) DEFAULT NULL,
`reviewed_time` datetime DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_claim_conflict` (`tenant_id`, `left_claim_id`, `right_claim_id`, `conflict_type`),
KEY `idx_aihr_claim_conflict_review` (`tenant_id`, `status`, `create_time`),
KEY `idx_aihr_claim_conflict_right` (`tenant_id`, `right_claim_id`),
CONSTRAINT `ck_aihr_claim_conflict_type` CHECK (`conflict_type` IN ('POLARITY','VALUE','APPLICABILITY')),
CONSTRAINT `ck_aihr_claim_conflict_status` CHECK (`status` IN ('PENDING_REVIEW','CONFIRMED','FALSE_POSITIVE','RESOLVED'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Claim-level conflicts requiring human arbitration';
SET @ddl := NULL;
@@ -0,0 +1,26 @@
-- Persist current data-quality alerts so production monitoring can page on stable reason codes.
-- Additive and idempotent on MySQL 8. Detectors only open or resolve operational alerts;
-- they never approve, publish, merge, supersede or delete knowledge assets.
CREATE TABLE IF NOT EXISTS `aihr_quality_alert` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`alert_code` varchar(64) NOT NULL,
`severity` varchar(20) NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'OPEN',
`message` varchar(500) NOT NULL,
`evidence_json` json DEFAULT NULL,
`occurrence_count` bigint NOT NULL DEFAULT 1,
`first_seen_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_seen_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`resolved_time` datetime DEFAULT NULL,
`detector_version` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_quality_alert_current` (`tenant_id`, `alert_code`),
KEY `idx_aihr_quality_alert_open` (`tenant_id`, `status`, `severity`, `last_seen_time`),
CONSTRAINT `ck_aihr_quality_alert_severity`
CHECK (`severity` IN ('WARNING','ERROR','CRITICAL')),
CONSTRAINT `ck_aihr_quality_alert_status`
CHECK (`status` IN ('OPEN','RESOLVED'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='Current operational data-quality alerts with auditable reason codes';
@@ -0,0 +1,28 @@
-- Human-governed tenant glossary used only for retrieval query expansion.
-- Definitions remain review metadata and are never injected into model prompts as facts.
CREATE TABLE IF NOT EXISTS `aihr_knowledge_glossary_term` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`term` varchar(120) NOT NULL,
`canonical_term` varchar(120) NOT NULL,
`aliases_json` json DEFAULT NULL,
`definition` varchar(2000) DEFAULT NULL,
`applicable_region` varchar(100) DEFAULT NULL,
`applicable_project` varchar(100) DEFAULT NULL,
`applicable_role` varchar(100) DEFAULT NULL,
`version_no` int NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'DRAFT',
`reviewer_id` bigint DEFAULT NULL,
`review_reason` varchar(500) DEFAULT NULL,
`reviewed_time` datetime DEFAULT NULL,
`create_by` bigint DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_glossary_version` (`tenant_id`, `term`, `version_no`),
KEY `idx_aihr_glossary_active` (`tenant_id`, `status`, `term`),
CONSTRAINT `ck_aihr_glossary_status`
CHECK (`status` IN ('DRAFT','ACTIVE','REJECTED','DEPRECATED'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='Immutable revisions of human-governed retrieval glossary terms';
@@ -0,0 +1,64 @@
-- Preserve AI case provenance after human approval. Approved synthetic cases remain synthetic.
SET @aihr_case_provenance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'synthetic_content'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `synthetic_content` tinyint(1) NOT NULL DEFAULT 0 COMMENT ''是否包含AI或确定性生成内容'' AFTER `owner`', 'SELECT 1');
PREPARE aihr_case_provenance_stmt FROM @aihr_case_provenance_ddl; EXECUTE aihr_case_provenance_stmt; DEALLOCATE PREPARE aihr_case_provenance_stmt;
SET @aihr_case_provenance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'generator_type'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `generator_type` varchar(40) DEFAULT NULL COMMENT ''real-llm/local-transcript'' AFTER `synthetic_content`', 'SELECT 1');
PREPARE aihr_case_provenance_stmt FROM @aihr_case_provenance_ddl; EXECUTE aihr_case_provenance_stmt; DEALLOCATE PREPARE aihr_case_provenance_stmt;
SET @aihr_case_provenance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'model_name'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `model_name` varchar(120) DEFAULT NULL COMMENT ''生成模型;本地规则为空'' AFTER `generator_type`', 'SELECT 1');
PREPARE aihr_case_provenance_stmt FROM @aihr_case_provenance_ddl; EXECUTE aihr_case_provenance_stmt; DEALLOCATE PREPARE aihr_case_provenance_stmt;
SET @aihr_case_provenance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'prompt_version'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `prompt_version` varchar(50) DEFAULT NULL COMMENT ''案例整理提示词版本'' AFTER `model_name`', 'SELECT 1');
PREPARE aihr_case_provenance_stmt FROM @aihr_case_provenance_ddl; EXECUTE aihr_case_provenance_stmt; DEALLOCATE PREPARE aihr_case_provenance_stmt;
SET @aihr_case_provenance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'grounding_oss_id'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `grounding_oss_id` bigint DEFAULT NULL COMMENT ''整理所依据的原始音频OSS'' AFTER `prompt_version`', 'SELECT 1');
PREPARE aihr_case_provenance_stmt FROM @aihr_case_provenance_ddl; EXECUTE aihr_case_provenance_stmt; DEALLOCATE PREPARE aihr_case_provenance_stmt;
SET @aihr_case_provenance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'ai_summary_hash'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `ai_summary_hash` char(64) DEFAULT NULL COMMENT ''AI整理摘要SHA-256'' AFTER `grounding_oss_id`', 'SELECT 1');
PREPARE aihr_case_provenance_stmt FROM @aihr_case_provenance_ddl; EXECUTE aihr_case_provenance_stmt; DEALLOCATE PREPARE aihr_case_provenance_stmt;
SET @aihr_case_provenance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'reviewer_id'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `reviewer_id` bigint DEFAULT NULL COMMENT ''人工审核人'' AFTER `ai_summary_hash`', 'SELECT 1');
PREPARE aihr_case_provenance_stmt FROM @aihr_case_provenance_ddl; EXECUTE aihr_case_provenance_stmt; DEALLOCATE PREPARE aihr_case_provenance_stmt;
SET @aihr_case_provenance_ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
AND table_name = 'aihr_case_record' AND column_name = 'reviewed_time'),
'ALTER TABLE `aihr_case_record` ADD COLUMN `reviewed_time` datetime DEFAULT NULL COMMENT ''人工审核时间'' AFTER `reviewer_id`', 'SELECT 1');
PREPARE aihr_case_provenance_stmt FROM @aihr_case_provenance_ddl; EXECUTE aihr_case_provenance_stmt; DEALLOCATE PREPARE aihr_case_provenance_stmt;
SET @aihr_case_provenance_index_exists := (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_case_record'
AND index_name = 'idx_aihr_case_synthetic_review'
);
SET @aihr_case_provenance_ddl := IF(@aihr_case_provenance_index_exists = 0,
'ALTER TABLE `aihr_case_record` ADD KEY `idx_aihr_case_synthetic_review` (`tenant_id`, `synthetic_content`, `status`, `reviewed_time`)',
'SELECT 1');
PREPARE aihr_case_provenance_stmt FROM @aihr_case_provenance_ddl;
EXECUTE aihr_case_provenance_stmt;
DEALLOCATE PREPARE aihr_case_provenance_stmt;
SET @aihr_case_provenance_index_exists := NULL;
SET @aihr_case_provenance_ddl := NULL;
@@ -0,0 +1,106 @@
-- Data-quality rule evolution evidence. Additive and safe to run repeatedly on MySQL 8.
-- This migration does not activate rules or change any asset lifecycle state.
CREATE TABLE IF NOT EXISTS `aihr_processing_rule` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`rule_code` varchar(64) NOT NULL,
`version_no` int NOT NULL,
`stage` varchar(30) NOT NULL,
`risk_class` varchar(20) NOT NULL,
`action` varchar(20) NOT NULL,
`implementation_type` varchar(30) NOT NULL,
`scope_json` json DEFAULT NULL,
`config_json` json NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'DRAFT',
`owner_id` bigint NOT NULL,
`supersedes_rule_id` bigint DEFAULT NULL,
`shadow_started_time` datetime DEFAULT NULL,
`retired_time` datetime DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_processing_rule_version` (`tenant_id`, `rule_code`, `version_no`),
KEY `idx_aihr_processing_rule_status` (`tenant_id`, `status`, `stage`, `update_time`),
CONSTRAINT `ck_aihr_processing_rule_stage` CHECK (`stage` IN
('INGESTION','PARSING','NORMALIZATION','STRUCTURING','DEDUPLICATION','PRIVACY','DOMAIN','QUALITY','PUBLISHING','INDEXING')),
CONSTRAINT `ck_aihr_processing_rule_risk` CHECK (`risk_class` IN ('LOW','MEDIUM','HIGH','CRITICAL')),
CONSTRAINT `ck_aihr_processing_rule_action` CHECK (`action` IN ('FLAG','REVIEW','QUARANTINE')),
CONSTRAINT `ck_aihr_processing_rule_implementation` CHECK (`implementation_type` IN
('DETERMINISTIC','STATISTICAL','LLM_ASSISTED')),
CONSTRAINT `ck_aihr_processing_rule_status` CHECK (`status` IN
('DRAFT','SHADOW','CANARY','ACTIVE','PAUSED','RETIRED'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Versioned data-quality processing rules';
CREATE TABLE IF NOT EXISTS `aihr_processing_rule_transition` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`rule_id` bigint NOT NULL,
`from_status` varchar(20) NOT NULL,
`to_status` varchar(20) NOT NULL,
`reason` varchar(500) NOT NULL,
`operator_id` bigint NOT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_aihr_rule_transition_rule` (`tenant_id`, `rule_id`, `create_time`),
CONSTRAINT `ck_aihr_rule_transition_from` CHECK (`from_status` IN
('DRAFT','SHADOW','CANARY','ACTIVE','PAUSED','RETIRED')),
CONSTRAINT `ck_aihr_rule_transition_to` CHECK (`to_status` IN
('DRAFT','SHADOW','CANARY','ACTIVE','PAUSED','RETIRED'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Audited processing-rule status transitions';
CREATE TABLE IF NOT EXISTS `aihr_rule_evaluation` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`rule_id` bigint NOT NULL,
`asset_id` bigint DEFAULT NULL,
`version_id` bigint DEFAULT NULL,
`sample_key` varchar(100) NOT NULL,
`evaluation_mode` varchar(20) NOT NULL DEFAULT 'SHADOW',
`expected_decision` varchar(20) NOT NULL,
`actual_decision` varchar(20) NOT NULL,
`confidence` decimal(6,5) DEFAULT NULL,
`expected_source` varchar(20) NOT NULL,
`matched_reason_codes_json` json DEFAULT NULL,
`false_allow` tinyint(1) NOT NULL DEFAULT 0,
`false_block` tinyint(1) NOT NULL DEFAULT 0,
`run_id` varchar(64) NOT NULL,
`evaluator_id` bigint NOT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_rule_evaluation_sample` (`tenant_id`, `rule_id`, `run_id`, `sample_key`),
KEY `idx_aihr_rule_evaluation_metrics` (`tenant_id`, `rule_id`, `evaluation_mode`, `create_time`),
KEY `idx_aihr_rule_evaluation_asset` (`tenant_id`, `asset_id`, `version_id`),
CONSTRAINT `ck_aihr_rule_evaluation_mode` CHECK (`evaluation_mode` IN ('SHADOW','CANARY')),
CONSTRAINT `ck_aihr_rule_expected_decision` CHECK (`expected_decision` IN ('PASS','REVIEW','BLOCK')),
CONSTRAINT `ck_aihr_rule_actual_decision` CHECK (`actual_decision` IN ('PASS','REVIEW','BLOCK')),
CONSTRAINT `ck_aihr_rule_expected_source` CHECK (`expected_source` IN ('HUMAN','GOLDEN')),
CONSTRAINT `ck_aihr_rule_false_allow` CHECK (`false_allow` IN (0,1)),
CONSTRAINT `ck_aihr_rule_false_block` CHECK (`false_block` IN (0,1))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Shadow and canary rule evaluations against human or golden labels';
CREATE TABLE IF NOT EXISTS `aihr_review_sample` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`rule_id` bigint NOT NULL,
`source_evaluation_id` bigint DEFAULT NULL,
`asset_id` bigint DEFAULT NULL,
`version_id` bigint DEFAULT NULL,
`sample_key` varchar(100) NOT NULL,
`sampling_strategy` varchar(30) NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'PENDING',
`review_result` varchar(30) DEFAULT NULL,
`review_note` varchar(1000) DEFAULT NULL,
`sampled_by` bigint NOT NULL,
`sampled_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`reviewed_by` bigint DEFAULT NULL,
`reviewed_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_review_sample` (`tenant_id`, `rule_id`, `sample_key`),
KEY `idx_aihr_review_sample_queue` (`tenant_id`, `status`, `sampling_strategy`, `sampled_time`),
CONSTRAINT `ck_aihr_review_sample_strategy` CHECK (`sampling_strategy` IN
('RANDOM','RISK_WEIGHTED','MISMATCH','MANUAL')),
CONSTRAINT `ck_aihr_review_sample_status` CHECK (`status` IN ('PENDING','REVIEWED')),
CONSTRAINT `ck_aihr_review_sample_result` CHECK (`review_result` IS NULL OR `review_result` IN
('CONFIRMED','FALSE_ALLOW','FALSE_BLOCK','NOT_APPLICABLE'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Risk-based human review samples for automated rule outcomes';
@@ -0,0 +1,34 @@
-- Replayable pipeline-run evidence and automatic shadow-review sampling.
-- Additive and safe to run repeatedly on MySQL 8. It never changes asset lifecycle state.
CREATE TABLE IF NOT EXISTS `aihr_pipeline_run` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`run_id` varchar(64) NOT NULL,
`asset_id` bigint DEFAULT NULL,
`input_version_id` bigint DEFAULT NULL,
`output_version_id` bigint DEFAULT NULL,
`stage` varchar(30) NOT NULL,
`processor_name` varchar(64) NOT NULL,
`processor_version` varchar(64) NOT NULL,
`trigger_type` varchar(30) NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'RUNNING',
`metrics_json` json DEFAULT NULL,
`error_code` varchar(64) DEFAULT NULL,
`error_message` varchar(1000) DEFAULT NULL,
`requested_by` bigint NOT NULL,
`started_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ended_time` datetime DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_pipeline_run` (`tenant_id`, `run_id`),
KEY `idx_aihr_pipeline_run_status` (`tenant_id`, `status`, `stage`, `started_time`),
KEY `idx_aihr_pipeline_run_asset` (`tenant_id`, `asset_id`, `input_version_id`),
CONSTRAINT `ck_aihr_pipeline_run_stage` CHECK (`stage` IN
('INGESTION','PARSING','NORMALIZATION','STRUCTURING','DEDUPLICATION','PRIVACY','DOMAIN','QUALITY','PUBLISHING','INDEXING')),
CONSTRAINT `ck_aihr_pipeline_run_trigger` CHECK (`trigger_type` IN
('MANUAL','SCHEDULED','REPROCESS','SHADOW_SAMPLING')),
CONSTRAINT `ck_aihr_pipeline_run_status` CHECK (`status` IN
('RUNNING','SUCCEEDED','FAILED','CANCELLED'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Replayable processing-stage and automatic-sampling run evidence';
@@ -0,0 +1,90 @@
-- Frozen golden datasets and explicit rule-acceptance evidence.
-- This migration never activates a rule or changes an asset, review decision, publication, or index.
CREATE TABLE IF NOT EXISTS `aihr_golden_dataset` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`dataset_code` varchar(64) NOT NULL,
`version_no` int NOT NULL,
`name` varchar(120) NOT NULL,
`description` varchar(1000) DEFAULT NULL,
`status` varchar(20) NOT NULL DEFAULT 'DRAFT',
`sample_count` int NOT NULL DEFAULT 0,
`content_hash` char(64) DEFAULT NULL,
`owner_id` bigint NOT NULL,
`frozen_by` bigint DEFAULT NULL,
`frozen_time` datetime DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_golden_dataset_version` (`tenant_id`, `dataset_code`, `version_no`),
KEY `idx_aihr_golden_dataset_status` (`tenant_id`, `status`, `update_time`),
CONSTRAINT `ck_aihr_golden_dataset_status` CHECK (`status` IN ('DRAFT','FROZEN','RETIRED')),
CONSTRAINT `ck_aihr_golden_dataset_sample_count` CHECK (`sample_count` >= 0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Immutable versions of human-labeled rule calibration datasets';
CREATE TABLE IF NOT EXISTS `aihr_golden_sample` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`dataset_id` bigint NOT NULL,
`sample_key` varchar(100) NOT NULL,
`risk_class` varchar(20) NOT NULL,
`expected_decision` varchar(20) NOT NULL,
`reason_codes_json` json DEFAULT NULL,
`evidence_ref` varchar(500) NOT NULL,
`asset_id` bigint DEFAULT NULL,
`version_id` bigint DEFAULT NULL,
`created_by` bigint NOT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_golden_sample` (`tenant_id`, `dataset_id`, `sample_key`),
KEY `idx_aihr_golden_sample_risk` (`tenant_id`, `dataset_id`, `risk_class`, `id`),
CONSTRAINT `ck_aihr_golden_sample_risk` CHECK (`risk_class` IN ('LOW','MEDIUM','HIGH','CRITICAL')),
CONSTRAINT `ck_aihr_golden_sample_decision` CHECK (`expected_decision` IN ('PASS','REVIEW','BLOCK'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Human-labeled samples belonging to a versioned golden dataset';
CREATE TABLE IF NOT EXISTS `aihr_rule_golden_evaluation` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`evaluation_id` bigint NOT NULL,
`dataset_id` bigint NOT NULL,
`golden_sample_id` bigint NOT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_rule_golden_evaluation` (`tenant_id`, `evaluation_id`),
KEY `idx_aihr_rule_golden_sample` (`tenant_id`, `golden_sample_id`, `evaluation_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Traceable link from a shadow evaluation to its frozen golden label';
CREATE TABLE IF NOT EXISTS `aihr_rule_acceptance_profile` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tenant_id` varchar(20) NOT NULL,
`rule_id` bigint NOT NULL,
`version_no` int NOT NULL,
`risk_class` varchar(20) NOT NULL,
`min_total_samples` int NOT NULL,
`min_golden_samples` int NOT NULL,
`min_reviewed_samples` int NOT NULL,
`min_agreement_rate` decimal(7,6) NOT NULL,
`max_false_allow_rate` decimal(7,6) NOT NULL,
`max_false_block_rate` decimal(7,6) NOT NULL,
`min_review_coverage_rate` decimal(7,6) NOT NULL,
`status` varchar(20) NOT NULL DEFAULT 'DRAFT',
`owner_id` bigint NOT NULL,
`freeze_reason` varchar(500) DEFAULT NULL,
`frozen_by` bigint DEFAULT NULL,
`frozen_time` datetime DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_aihr_rule_acceptance_profile` (`tenant_id`, `rule_id`, `version_no`),
KEY `idx_aihr_rule_acceptance_status` (`tenant_id`, `rule_id`, `status`, `version_no`),
CONSTRAINT `ck_aihr_rule_acceptance_risk` CHECK (`risk_class` IN ('LOW','MEDIUM','HIGH','CRITICAL')),
CONSTRAINT `ck_aihr_rule_acceptance_status` CHECK (`status` IN ('DRAFT','FROZEN','RETIRED')),
CONSTRAINT `ck_aihr_rule_acceptance_counts` CHECK (
`min_total_samples` >= 1 AND `min_golden_samples` >= 1 AND `min_reviewed_samples` >= 1),
CONSTRAINT `ck_aihr_rule_acceptance_rates` CHECK (
`min_agreement_rate` BETWEEN 0 AND 1 AND
`max_false_allow_rate` BETWEEN 0 AND 1 AND
`max_false_block_rate` BETWEEN 0 AND 1 AND
`min_review_coverage_rate` BETWEEN 0 AND 1)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Frozen, risk-specific evidence thresholds for a processing-rule version';
@@ -0,0 +1,74 @@
-- Versioned privacy derivatives for governed knowledge assets.
-- Existing versions remain NOT_PROCESSED and cannot be published until they are restaged from the immutable source.
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'normalized_content_sha256'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `normalized_content_sha256` char(64) DEFAULT NULL AFTER `normalized_content`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'redacted_content'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `redacted_content` longtext DEFAULT NULL AFTER `normalized_content_sha256`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'redacted_source_name'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `redacted_source_name` varchar(500) DEFAULT NULL AFTER `redacted_content`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'redacted_content_sha256'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `redacted_content_sha256` char(64) DEFAULT NULL AFTER `redacted_source_name`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'privacy_status'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `privacy_status` varchar(20) NOT NULL DEFAULT ''NOT_PROCESSED'' AFTER `redacted_content_sha256`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'redaction_policy_version'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `redaction_policy_version` varchar(50) DEFAULT NULL AFTER `privacy_status`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND column_name = 'redaction_summary_json'),
'ALTER TABLE `aihr_data_version` ADD COLUMN `redaction_summary_json` json DEFAULT NULL AFTER `redaction_policy_version`',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl := IF(
NOT EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'aihr_data_version'
AND index_name = 'idx_aihr_data_version_privacy'),
'ALTER TABLE `aihr_data_version` ADD KEY `idx_aihr_data_version_privacy` (`tenant_id`,`privacy_status`,`id`)',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;