{"repo": "2020dfff/rbac-text2sql-benchmark", "files": {"notebooks/bird_column_level_rbac.ipynb": {"54d344296bbc44b61df84eebf4dd55021ecc3198": {"t": 1785745476.6476693, "n": 162988, "h": "a254ef89eada166d", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"id\": \"c4bddd25\",\n \"metadata\": {},\n \"source\": [\n \"## 0. Import and Setup\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"93292a4c\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Setup and imports\\n\",\n \"import sys\\n\",\n \"import json\\n\",\n \"import sqlite3\\n\",\n \"from pathlib import Path\\n\",\n \"from pprint import pprint\\n\",\n \"\\n\",\n \"# Add project root to path\\n\",\n \"project_root = Path.cwd().parent\\n\",\n \"sys.path.insert(0, str(project_root))\\n\",\n \"\\n\",\n \"print(f\\\"Project root: {project_root}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 2,\n \"id\": \"bce399e4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Available API keys:\\n\",\n \" OPENAI_API_KEY: ✓\\n\",\n \" DEEPSEEK_API_KEY: ✓\\n\",\n \" DEEPINFRA_API_KEY: ✓\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Load environment and initialize Oracle\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"import os\\n\",\n \"\\n\",\n \"load_dotenv(project_root / '.env')\\n\",\n \"\\n\",\n \"# Check available API keys\\n\",\n \"api_keys = {\\n\",\n \" 'OPENAI_API_KEY': bool(os.getenv('OPENAI_API_KEY')),\\n\",\n \" 'DEEPSEEK_API_KEY': bool(os.getenv('DEEPSEEK_API_KEY')),\\n\",\n \" 'DEEPINFRA_API_KEY': bool(os.getenv('DEEPINFRA_API_KEY')),\\n\",\n \"}\\n\",\n \"print(\\\"Available API keys:\\\")\\n\",\n \"for k, v in api_keys.items():\\n\",\n \" print(f\\\" {k}: {'✓' if v else '✗'}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"a4d69b7c\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Initialize LLM Oracle\\n\",\n \"from src.llm_oracle import Oracle\\n\",\n \"\\n\",\n \"# Choose model based on available keys (prefer DeepSeek for cost efficiency)\\n\",\n \"if os.getenv('DEEPSEEK_API_KEY'):\\n\",\n \" MODEL = \\\"deepseek-chat\\\"\\n\",\n \" API_KEY = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"elif os.getenv('OPENAI_API_KEY'):\\n\",\n \" MODEL = \\\"gpt-4o-mini\\\"\\n\",\n \" API_KEY = os.getenv('OPENAI_API_KEY')\\n\",\n \"else:\\n\",\n \" raise ValueError(\\\"No API key available!\\\")\\n\",\n \"\\n\",\n \"oracle = Oracle(model=MODEL, apikey=API_KEY)\\n\",\n \"print(f\\\"Using model: {MODEL}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8809cf55\",\n \"metadata\": {},\n \"source\": [\n \"## 1. Load Sample Database Schema\\n\",\n \"\\n\",\n \"We'll use a BIRD database with interesting column structure for testing.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 4,\n \"id\": \"e9dcc61c\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Import shared policy utility functions\\n\",\n \"from src.role_evaluator.quality_metrics import RoleQualityEvaluator\\n\",\n \"\\n\",\n \"# Convenience aliases for the static methods\\n\",\n \"count_policy_columns = RoleQualityEvaluator.count_policy_columns\\n\",\n \"has_wildcard_policy = RoleQualityEvaluator.has_wildcard_policy\\n\",\n \"\\n\",\n \"def get_schema_from_sqlite(db_path: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Extract detailed schema from SQLite database.\\\"\\\"\\\"\\n\",\n \" conn = sqlite3.connect(db_path)\\n\",\n \" cursor = conn.cursor()\\n\",\n \" \\n\",\n \" # Get all tables\\n\",\n \" cursor.execute(\\\"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'\\\")\\n\",\n \" tables = [row[0] for row in cursor.fetchall()]\\n\",\n \" \\n\",\n \" schema = {}\\n\",\n \" for table in tables:\\n\",\n \" cursor.execute(f\\\"PRAGMA table_info(`{table}`)\\\")\\n\",\n \" columns = cursor.fetchall()\\n\",\n \" \\n\",\n \" cursor.execute(f\\\"PRAGMA foreign_key_list(`{table}`)\\\")\\n\",\n \" fks = {row[3]: f\\\"{row[2]}.{row[4]}\\\" for row in cursor.fetchall()}\\n\",\n \" \\n\",\n \" schema[table] = {\\n\",\n \" 'columns': [\\n\",\n \" {\\n\",\n \" 'name': col[1],\\n\",\n \" 'type': col[2] or 'TEXT',\\n\",\n \" 'pk': col[5] == 1,\\n\",\n \" 'not_null': col[3] == 1,\\n\",\n \" 'fk': fks.get(col[1])\\n\",\n \" }\\n\",\n \" for col in columns\\n\",\n \" ]\\n\",\n \" }\\n\",\n \" \\n\",\n \" conn.close()\\n\",\n \" return schema\\n\",\n \"\\n\",\n \"def format_schema_for_prompt(schema: dict, db_name: str) -> str:\\n\",\n \" \\\"\\\"\\\"Format schema as text for LLM prompt.\\\"\\\"\\\"\\n\",\n \" lines = [f\\\"Database: {db_name}\\\\n\\\"]\\n\",\n \" \\n\",\n \" for table, info in schema.items():\\n\",\n \" lines.append(f\\\"Table: {table}\\\")\\n\",\n \" lines.append(\\\"Columns:\\\")\\n\",\n \" for col in info['columns']:\\n\",\n \" constraints = []\\n\",\n \" if col['pk']:\\n\",\n \" constraints.append(\\\"PRIMARY KEY\\\")\\n\",\n \" if col['not_null'] and not col['pk']:\\n\",\n \" constraints.append(\\\"NOT NULL\\\")\\n\",\n \" if col['fk']:\\n\",\n \" constraints.append(f\\\"FK -> {col['fk']}\\\")\\n\",\n \" \\n\",\n \" constraint_str = f\\\" [{', '.join(constraints)}]\\\" if constraints else \\\"\\\"\\n\",\n \" lines.append(f\\\" - {col['name']} ({col['type']}){constraint_str}\\\")\\n\",\n \" lines.append(\\\"\\\")\\n\",\n \" \\n\",\n \" return \\\"\\\\n\\\".join(lines)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 5,\n \"id\": \"705d64b1\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Available BIRD databases (11):\\n\",\n \" - california_schools\\n\",\n \" - card_games\\n\",\n \" - codebase_community\\n\",\n \" - debit_card_specializing\\n\",\n \" - european_football_2\\n\",\n \" - financial\\n\",\n \" - formula_1\\n\",\n \" - student_club\\n\",\n \" - superhero\\n\",\n \" - thrombosis_prediction\\n\",\n \" ...\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Load a sample BIRD database - use the latest 2025 version\\n\",\n \"bird_db_dir = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases'\\n\",\n \"\\n\",\n \"# List available databases\\n\",\n \"available_dbs = [d.name for d in bird_db_dir.iterdir() if d.is_dir()]\\n\",\n \"print(f\\\"Available BIRD databases ({len(available_dbs)}):\\\")\\n\",\n \"for db in sorted(available_dbs)[:10]:\\n\",\n \" print(f\\\" - {db}\\\")\\n\",\n \"print(\\\" ...\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"f9e1a86a\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Select a database with moderate complexity\\n\",\n \"# 'california_schools' has tables with sensitive-looking columns\\n\",\n \"TEST_DB = \\\"california_schools\\\"\\n\",\n \"db_path = bird_db_dir / TEST_DB / f\\\"{TEST_DB}.sqlite\\\"\\n\",\n \"\\n\",\n \"print(f\\\"Loading schema from: {db_path}\\\")\\n\",\n \"schema = get_schema_from_sqlite(str(db_path))\\n\",\n \"\\n\",\n \"print(f\\\"\\\\nTables: {list(schema.keys())}\\\")\\n\",\n \"for table, info in schema.items():\\n\",\n \" print(f\\\"\\\\n{table}: {len(info['columns'])} columns\\\")\\n\",\n \" for col in info['columns'][:5]:\\n\",\n \" print(f\\\" - {col['name']} ({col['type']})\\\")\\n\",\n \" if len(info['columns']) > 5:\\n\",\n \" print(f\\\" ... and {len(info['columns']) - 5} more\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 7,\n \"id\": \"e5fb0114\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Database: california_schools\\n\",\n \"\\n\",\n \"Table: frpm\\n\",\n \"Columns:\\n\",\n \" - CDSCode (TEXT) [PRIMARY KEY, FK -> schools.CDSCode]\\n\",\n \" - Academic Year (TEXT)\\n\",\n \" - County Code (TEXT)\\n\",\n \" - District Code (INTEGER)\\n\",\n \" - School Code (TEXT)\\n\",\n \" - County Name (TEXT)\\n\",\n \" - District Name (TEXT)\\n\",\n \" - School Name (TEXT)\\n\",\n \" - District Type (TEXT)\\n\",\n \" - School Type (TEXT)\\n\",\n \" - Educational Option Type (TEXT)\\n\",\n \" - NSLP Provision Status (TEXT)\\n\",\n \" - Charter School (Y/N) (INTEGER)\\n\",\n \" - Charter School Number (TEXT)\\n\",\n \" - Charter Funding Type (TEXT)\\n\",\n \" - IRC (INTEGER)\\n\",\n \" - Low Grade (TEXT)\\n\",\n \" - High Grade (TEXT)\\n\",\n \" - Enrollment (K-12) (REAL)\\n\",\n \" - Free Meal Count (K-12) (REAL)\\n\",\n \" - Percent (%) Eligible Free (K-12) (REAL)\\n\",\n \" - FRPM Count (K-12) (REAL)\\n\",\n \" - Percent (%) Eligible FRPM (K-12) (REAL)\\n\",\n \" - Enrollment (Ages 5-17) (REAL)\\n\",\n \" - Free Meal Count (Ages 5-17) (REAL)\\n\",\n \" - Percent (%) Eligible Free (Ages 5-17) (REAL)\\n\",\n \" - FRPM Count (Ages 5-17) (REAL)\\n\",\n \" - Percent (%) Eligible FRPM (Ages 5-17) (REAL)\\n\",\n \" - 2013-14 CALPADS Fall 1 Certification Status (INTEGER)\\n\",\n \"\\n\",\n \"Table: satscores\\n\",\n \"Columns:\\n\",\n \" - cds (TEXT) [PRIMARY KEY, FK -> schools.CDSCode]\\n\",\n \" - rtype (TEXT) [NOT NULL]\\n\",\n \" - sname (TEXT)\\n\",\n \" - dname (TEXT)\\n\",\n \" - cname (TEXT)\\n\",\n \" - enroll12 (INTEGER) [NOT NULL]\\n\",\n \" - NumTstTakr (INTEGER) [NOT NULL]\\n\",\n \" - AvgScrRead (INTEGER)\\n\",\n \" - AvgScrMath (INTEGER)\\n\",\n \" - AvgScrWrite (INTEGER)\\n\",\n \" - NumGE1500 (INTEGER)\\n\",\n \"\\n\",\n \"Table: schools\\n\",\n \"Columns:\\n\",\n \" - CDSCode (TEXT) [PRIMARY KEY]\\n\",\n \" - NCESDist (TEXT)\\n\",\n \" - NCESSchool (TEXT)\\n\",\n \" - StatusType (TEXT) [NOT NULL]\\n\",\n \" - County (TEXT) [NOT NULL]\\n\",\n \" - District (TEXT) [NOT NULL]\\n\",\n \" - School (TEXT)\\n\",\n \" - Street (TEXT)\\n\",\n \" - StreetAbr (TEXT)\\n\",\n \" - City (TEXT)\\n\",\n \" - Zip (TEXT)\\n\",\n \" - State (TEXT)\\n\",\n \" - MailStreet (TEXT)\\n\",\n \" - MailStrAbr (TEXT)\\n\",\n \" - MailCity (TEXT)\\n\",\n \" - MailZip (TEXT)\\n\",\n \" - MailState (TEXT)\\n\",\n \" - Phone (TEXT)\\n\",\n \" - Ext (TEXT)\\n\",\n \" - Website (TEXT)\\n\",\n \" - OpenDate (DATE)\\n\",\n \" - ClosedDate (DATE)\\n\",\n \" - Charter (INTEGER)\\n\",\n \" - CharterNum (TEXT)\\n\",\n \" - FundingType (TEXT)\\n\",\n \" - DOC (TEXT) [NOT NULL]\\n\",\n \" - DOCType (TEXT) [NOT NULL]\\n\",\n \" - SOC (TEXT)\\n\",\n \" - SOCType (TEXT)\\n\",\n \" - EdOpsCode (TEXT)\\n\",\n \" \\n\",\n \"\\n\",\n \"... (total 2401 characters)\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Format schema for prompt\\n\",\n \"schema_text = format_schema_for_prompt(schema, TEST_DB)\\n\",\n \"print(schema_text[:2000])\\n\",\n \"print(f\\\"\\\\n... (total {len(schema_text)} characters)\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8e904509\",\n \"metadata\": {},\n \"source\": [\n \"## 2. Load Prompts from External Modules\\n\",\n \"\\n\",\n \"Prompts are now defined in `configs/column_level_prompts.py`.\\n\",\n \"- **JSON format** is used (more structured, requires max_tokens=4000)\\n\",\n \"- Parser auto-detects format and handles both JSON and Plain Text\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 8,\n \"id\": \"1a425645\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Loaded from external modules:\\n\",\n \" - COLUMN_LEVEL_SYSTEM_PROMPT (2734 chars)\\n\",\n \" - COLUMN_LEVEL_USER_PROMPT_TEMPLATE\\n\",\n \" - DEFAULT_MAX_TOKENS = 4000\\n\",\n \" - parse_column_level_roles (auto-detects JSON/Text)\\n\",\n \" - validate_roles_against_schema\\n\",\n \"\\n\",\n \"--- System Prompt Preview ---\\n\",\n \"You are a database security expert specializing in fine-grained Role-Based Access Control (RBAC).\\n\",\n \"Your job is to read a relational database schema and propose a COHERENT set of roles with COLUMN-LEVEL permissions.\\n\",\n \"\\n\",\n \"Key goals:\\n\",\n \"- Minimize role count while covering real-world workflows (decide number of roles according to real world scenario).\\n\",\n \"- Each role must be clearly related to others (same scenario, complementary duties).\\n\",\n \"- Enforce least-privilege at the COLUMN level (specify which columns eac\\n\",\n \"...\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Reload modules to get latest changes\\n\",\n \"import importlib\\n\",\n \"import configs.column_level_prompts\\n\",\n \"import src.role_parser.column_level_parser\\n\",\n \"importlib.reload(configs.column_level_prompts)\\n\",\n \"importlib.reload(src.role_parser.column_level_parser)\\n\",\n \"\\n\",\n \"# Import prompts and parser from external modules\\n\",\n \"from configs.column_level_prompts import (\\n\",\n \" COLUMN_LEVEL_SYSTEM_PROMPT, \\n\",\n \" COLUMN_LEVEL_USER_PROMPT_TEMPLATE,\\n\",\n \" DEFAULT_MAX_TOKENS\\n\",\n \")\\n\",\n \"from src.role_parser import parse_column_level_roles, validate_roles_against_schema\\n\",\n \"\\n\",\n \"print(\\\"✓ Loaded from external modules:\\\")\\n\",\n \"print(f\\\" - COLUMN_LEVEL_SYSTEM_PROMPT ({len(COLUMN_LEVEL_SYSTEM_PROMPT)} chars)\\\")\\n\",\n \"print(f\\\" - COLUMN_LEVEL_USER_PROMPT_TEMPLATE\\\")\\n\",\n \"print(f\\\" - DEFAULT_MAX_TOKENS = {DEFAULT_MAX_TOKENS}\\\")\\n\",\n \"print(f\\\" - parse_column_level_roles (auto-detects JSON/Text)\\\")\\n\",\n \"print(f\\\" - validate_roles_against_schema\\\")\\n\",\n \"\\n\",\n \"print(\\\"\\\\n--- System Prompt Preview ---\\\")\\n\",\n \"print(COLUMN_LEVEL_SYSTEM_PROMPT[:500])\\n\",\n \"print(\\\"...\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"0acacb6e\",\n \"metadata\": {},\n \"source\": [\n \"## [Archived] Single-Sample Experiments\\n\",\n \"\\n\",\n \"The following code block contains single sample test code for debugging prompt and parser.\\n\",\n \"**Commented out. For production, skip to Section 8 for batch processing.**\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 9,\n \"id\": \"e9700ae1\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"⏭️ This cell is commented out. Skip to Section 8 for batch processing.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# ============================================================\\n\",\n \"# [ARCHIVED] Single sample experiment code - commented out, skip this cell\\n\",\n \"# ============================================================\\n\",\n \"# The following code is for testing and debugging a single database\\n\",\n \"# For production, skip to Section 8 for batch processing\\n\",\n \"\\n\",\n \"'''\\n\",\n \"# --- 3. Generate Column-Level Roles (Single DB) ---\\n\",\n \"print(\\\"Generating column-level roles...\\\")\\n\",\n \"user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=schema_text)\\n\",\n \"response = oracle.query(\\n\",\n \" prompt_sys=COLUMN_LEVEL_SYSTEM_PROMPT,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3, top_p=0.9,\\n\",\n \" max_completion_tokens=DEFAULT_MAX_TOKENS\\n\",\n \")\\n\",\n \"llm_response = response['answer']\\n\",\n \"print(f\\\"Response length: {len(llm_response)} chars\\\")\\n\",\n \"\\n\",\n \"# --- 4. Parse and Validate ---\\n\",\n \"from src.role_parser.column_level_parser import parse_column_level_roles\\n\",\n \"parsed_roles = parse_column_level_roles(llm_response)\\n\",\n \"print(f\\\"Parsed {len(parsed_roles)} roles\\\")\\n\",\n \"\\n\",\n \"validation = validate_roles_against_schema(parsed_roles, str(db_path))\\n\",\n \"print(f\\\"Valid: {validation['valid_roles']}/{validation['total_roles']}\\\")\\n\",\n \"\\n\",\n \"# --- 5. Show Results ---\\n\",\n \"for role in parsed_roles:\\n\",\n \" print(f\\\" - {role['role']}: {len(role.get('columns', {}))} tables\\\")\\n\",\n \"\\n\",\n \"# --- 6. Compare with Table-Level ---\\n\",\n \"from configs.prompts import SYSTEM_PROMPT as TABLE_LEVEL_PROMPT, USER_PROMPT_TEMPLATE\\n\",\n \"table_level_response = oracle.query(\\n\",\n \" prompt_sys=TABLE_LEVEL_PROMPT,\\n\",\n \" prompt_user=USER_PROMPT_TEMPLATE.format(schema_content=schema_text),\\n\",\n \" temp=0.3, top_p=0.9\\n\",\n \")\\n\",\n \"print(\\\"Table-Level Response:\\\", table_level_response['answer'][:500])\\n\",\n \"\\n\",\n \"# --- 7. Save Single DB Result ---\\n\",\n \"def convert_to_assignment_format(parsed_roles, db_name):\\n\",\n \" return {\\\"assignments\\\": {db_name: [\\n\",\n \" {\\\"role\\\": r[\\\"role\\\"], \\\"description\\\": r.get(\\\"description\\\", \\\"\\\"), \\\"policy\\\": r.get(\\\"columns\\\", {})}\\n\",\n \" for r in parsed_roles\\n\",\n \" ]}}\\n\",\n \"\\n\",\n \"column_level_assignments = convert_to_assignment_format(parsed_roles, TEST_DB)\\n\",\n \"output_file = project_root / 'outputs' / 'column_level_role_assignments.json'\\n\",\n \"with open(output_file, 'w') as f:\\n\",\n \" json.dump(column_level_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \"print(f\\\"Saved to: {output_file}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ This cell is commented out. Skip to Section 8 for batch processing.\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8bc8cb95\",\n \"metadata\": {},\n \"source\": [\n \"## 3. Batch Process All BIRD Databases\\n\",\n \"\\n\",\n \"Generate column-level role assignments for all BIRD databases with parallel processing.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 10,\n \"id\": \"fe3f2e81\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Configuration:\\n\",\n \" Workers: 40\\n\",\n \" Databases: 11\\n\",\n \" Max tokens: 4000\\n\",\n \" Model: deepseek-chat\\n\",\n \"\\n\",\n \"Databases to process:\\n\",\n \" - superhero\\n\",\n \" - thrombosis_prediction\\n\",\n \" - student_club\\n\",\n \" - toxicology\\n\",\n \" - california_schools\\n\",\n \" - debit_card_specializing\\n\",\n \" - card_games\\n\",\n \" - codebase_community\\n\",\n \" - formula_1\\n\",\n \" - european_football_2\\n\",\n \" - financial\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Batch processing configuration\\n\",\n \"from concurrent.futures import ThreadPoolExecutor, as_completed\\n\",\n \"from tqdm.notebook import tqdm\\n\",\n \"\\n\",\n \"# Configuration\\n\",\n \"WORKERS = 40\\n\",\n \"SAMPLES = 100 # 0 for all databases\\n\",\n \"MAX_TOKENS = DEFAULT_MAX_TOKENS\\n\",\n \"\\n\",\n \"# Get all BIRD databases\\n\",\n \"all_dbs = [d.name for d in bird_db_dir.iterdir() if d.is_dir()]\\n\",\n \"if SAMPLES > 0:\\n\",\n \" all_dbs = all_dbs[:SAMPLES]\\n\",\n \"\\n\",\n \"print(f\\\"Configuration:\\\")\\n\",\n \"print(f\\\" Workers: {WORKERS}\\\")\\n\",\n \"print(f\\\" Databases: {len(all_dbs)}\\\")\\n\",\n \"print(f\\\" Max tokens: {MAX_TOKENS}\\\")\\n\",\n \"print(f\\\" Model: {MODEL}\\\")\\n\",\n \"print(f\\\"\\\\nDatabases to process:\\\")\\n\",\n \"for db in all_dbs:\\n\",\n \" print(f\\\" - {db}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 11,\n \"id\": \"7b5edd94\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Helper functions defined\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Helper functions for batch processing\\n\",\n \"\\n\",\n \"def process_single_database(db_name: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Process a single database and return role assignments.\\\"\\\"\\\"\\n\",\n \" db_path = bird_db_dir / db_name / f\\\"{db_name}.sqlite\\\"\\n\",\n \" \\n\",\n \" if not db_path.exists():\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": f\\\"Database not found\\\"}\\n\",\n \" \\n\",\n \" try:\\n\",\n \" # Extract schema\\n\",\n \" db_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" db_schema_text = format_schema_for_prompt(db_schema, db_name)\\n\",\n \" \\n\",\n \" # Generate roles via LLM\\n\",\n \" user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=db_schema_text)\\n\",\n \" \\n\",\n \" response = oracle.query(\\n\",\n \" prompt_sys=COLUMN_LEVEL_SYSTEM_PROMPT,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3,\\n\",\n \" top_p=0.9,\\n\",\n \" max_completion_tokens=MAX_TOKENS\\n\",\n \" )\\n\",\n \" \\n\",\n \" llm_response = response['answer']\\n\",\n \" usage = response.get('usage', {})\\n\",\n \" \\n\",\n \" # Parse response\\n\",\n \" roles = parse_column_level_roles(llm_response)\\n\",\n \" \\n\",\n \" if not roles:\\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"parse_error\\\",\\n\",\n \" \\\"error\\\": \\\"Failed to parse LLM response\\\",\\n\",\n \" \\\"raw_response\\\": llm_response[:300]\\n\",\n \" }\\n\",\n \" \\n\",\n \" # Validate against schema\\n\",\n \" validation = validate_roles_against_schema(roles, str(db_path))\\n\",\n \" \\n\",\n \" # Convert to target format\\n\",\n \" assignments = []\\n\",\n \" for role in roles:\\n\",\n \" assignments.append({\\n\",\n \" \\\"role\\\": role[\\\"role\\\"],\\n\",\n \" \\\"description\\\": role.get(\\\"description\\\", \\\"\\\"),\\n\",\n \" \\\"policy\\\": role.get(\\\"columns\\\", {})\\n\",\n \" })\\n\",\n \" \\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"success\\\",\\n\",\n \" \\\"roles_count\\\": len(assignments),\\n\",\n \" \\\"valid_roles\\\": validation['valid_roles'],\\n\",\n \" \\\"all_valid\\\": validation['all_valid'],\\n\",\n \" \\\"assignments\\\": assignments,\\n\",\n \" \\\"usage\\\": usage\\n\",\n \" }\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"error\\\",\\n\",\n \" \\\"error\\\": str(e)\\n\",\n \" }\\n\",\n \"\\n\",\n \"print(\\\"✓ Helper functions defined\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 12,\n \"id\": \"61e61795\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Starting batch processing with 40 workers...\\n\",\n \"============================================================\\n\",\n \"[1/11] ✓ toxicology: 4 roles (4 valid)\\n\",\n \"[2/11] ✓ debit_card_specializing: 4 roles (4 valid)\\n\",\n \"[3/11] ✓ thrombosis_prediction: 4 roles (4 valid)\\n\",\n \"[4/11] ✓ student_club: 5 roles (5 valid)\\n\",\n \"[5/11] ✓ superhero: 5 roles (5 valid)\\n\",\n \"[6/11] ✓ financial: 5 roles (5 valid)\\n\",\n \"[7/11] ✓ card_games: 5 roles (5 valid)\\n\",\n \"[8/11] ✓ codebase_community: 4 roles (4 valid)\\n\",\n \"[9/11] ✓ california_schools: 5 roles (5 valid)\\n\",\n \"[10/11] ✓ formula_1: 5 roles (5 valid)\\n\",\n \"[11/11] ✓ european_football_2: 5 roles (5 valid)\\n\",\n \"============================================================\\n\",\n \"Completed: 11/11 success, 0 errors\\n\",\n \"Total tokens: 25,679\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Execute batch processing with parallel workers\\n\",\n \"print(f\\\"Starting batch processing with {WORKERS} workers...\\\")\\n\",\n \"print(\\\"=\\\" * 60)\\n\",\n \"\\n\",\n \"results = {\\n\",\n \" \\\"metadata\\\": {\\n\",\n \" \\\"model\\\": MODEL,\\n\",\n \" \\\"max_tokens\\\": MAX_TOKENS,\\n\",\n \" \\\"total_databases\\\": len(all_dbs)\\n\",\n \" },\\n\",\n \" \\\"assignments\\\": {},\\n\",\n \" \\\"errors\\\": []\\n\",\n \"}\\n\",\n \"\\n\",\n \"success_count = 0\\n\",\n \"error_count = 0\\n\",\n \"total_tokens = {\\\"prompt\\\": 0, \\\"completion\\\": 0}\\n\",\n \"\\n\",\n \"with ThreadPoolExecutor(max_workers=WORKERS) as executor:\\n\",\n \" futures = {executor.submit(process_single_database, db): db for db in all_dbs}\\n\",\n \" \\n\",\n \" for i, future in enumerate(as_completed(futures), 1):\\n\",\n \" db_name = futures[future]\\n\",\n \" try:\\n\",\n \" result = future.result()\\n\",\n \" \\n\",\n \" if result[\\\"status\\\"] == \\\"success\\\":\\n\",\n \" results[\\\"assignments\\\"][result[\\\"database\\\"]] = result[\\\"assignments\\\"]\\n\",\n \" success_count += 1\\n\",\n \" \\n\",\n \" usage = result.get(\\\"usage\\\", {})\\n\",\n \" total_tokens[\\\"prompt\\\"] += usage.get(\\\"prompt_tokens\\\", 0)\\n\",\n \" total_tokens[\\\"completion\\\"] += usage.get(\\\"completion_tokens\\\", 0)\\n\",\n \" \\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✓ {db_name}: {result['roles_count']} roles ({result['valid_roles']} valid)\\\")\\n\",\n \" else:\\n\",\n \" results[\\\"errors\\\"].append(result)\\n\",\n \" error_count += 1\\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✗ {db_name}: {result.get('error', result['status'])}\\\")\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" error_count += 1\\n\",\n \" results[\\\"errors\\\"].append({\\\"database\\\": db_name, \\\"error\\\": str(e)})\\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✗ {db_name}: {e}\\\")\\n\",\n \"\\n\",\n \"results[\\\"metadata\\\"][\\\"success_count\\\"] = success_count\\n\",\n \"results[\\\"metadata\\\"][\\\"error_count\\\"] = error_count\\n\",\n \"results[\\\"metadata\\\"][\\\"total_tokens\\\"] = total_tokens\\n\",\n \"\\n\",\n \"print(\\\"=\\\" * 60)\\n\",\n \"print(f\\\"Completed: {success_count}/{len(all_dbs)} success, {error_count} errors\\\")\\n\",\n \"print(f\\\"Total tokens: {total_tokens['prompt'] + total_tokens['completion']:,}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"39d38aa3\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Save batch results to file\\n\",\n \"output_file = project_root / 'outputs' / 'column_level_role_assignments_bird.json'\\n\",\n \"\\n\",\n \"with open(output_file, 'w', encoding='utf-8') as f:\\n\",\n \" json.dump(results, f, indent=2, ensure_ascii=False)\\n\",\n \"\\n\",\n \"print(f\\\"✓ Results saved to: {output_file}\\\")\\n\",\n \"print(f\\\"\\\\nFile structure:\\\")\\n\",\n \"print(f\\\" - metadata: model, tokens, counts\\\")\\n\",\n \"print(f\\\" - assignments: {len(results['assignments'])} databases\\\")\\n\",\n \"print(f\\\" - errors: {len(results['errors'])} entries\\\")\\n\",\n \"\\n\",\n \"# Show sample\\n\",\n \"if results['assignments']:\\n\",\n \" sample_db = list(results['assignments'].keys())[0]\\n\",\n \" print(f\\\"\\\\nSample ({sample_db}):\\\")\\n\",\n \" print(json.dumps(results['assignments'][sample_db][:1], indent=2, ensure_ascii=False)[:500])\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"9595c46d\",\n \"metadata\": {},\n \"source\": [\n \"## 4. Generate Column-Level RBAC Dataset\\n\",\n \"\\n\",\n \"Based on the generated role policies, combined with BIRD dataset queries, generate the final RBAC training/evaluation dataset.\\n\",\n \"\\n\",\n \"Dataset format (consistent with table-level):\\n\",\n \"- `db_id`: Database name\\n\",\n \"- `instruction`: Full instruction with schema + evidence + role policy\\n\",\n \"- `role`: Role name\\n\",\n \"- `policy`: Column-level permission policy {table: [columns]}\\n\",\n \"- `input`: User question\\n\",\n \"- `output`: SQL or denial message\\n\",\n \"- `difficulty`: Query difficulty level\\n\",\n \"- `metadata`: Contains gold_sql, permission, query_columns, missing_columns, etc.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"405783fa\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 4.1 Import generator and test dependencies\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator, format_policy_text\\n\",\n \"from src.processors.column_extractor import extract_query_columns\\n\",\n \"from src.processors.column_permission_checker import check_column_permission\\n\",\n \"import glob\\n\",\n \"\\n\",\n \"# Configure paths - use 2025 version (dev_20251106) for latest BIRD data\\n\",\n \"ROLE_ASSIGNMENTS_PATH = project_root / 'outputs' / 'column_level_role_assignments_bird.json'\\n\",\n \"BIRD_DATA_PATH = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev.json'\\n\",\n \"BIRD_DB_ROOT = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases'\\n\",\n \"\\n\",\n \"print(\\\"=== Dataset Generation Config ===\\\")\\n\",\n \"print(f\\\"Role assignments: {ROLE_ASSIGNMENTS_PATH}\\\")\\n\",\n \"print(f\\\"BIRD data file: {BIRD_DATA_PATH}\\\")\\n\",\n \"print(f\\\"BIRD database dir: {BIRD_DB_ROOT}\\\")\\n\",\n \"\\n\",\n \"# Verify file existence\\n\",\n \"# assert ROLE_ASSIGNMENTS_PATH.exists(), f\\\"Role assignments file not found: {ROLE_ASSIGNMENTS_PATH}\\\"\\n\",\n \"assert BIRD_DATA_PATH.exists(), f\\\"BIRD data file not found: {BIRD_DATA_PATH}\\\"\\n\",\n \"assert BIRD_DB_ROOT.exists(), f\\\"BIRD database dir not found: {BIRD_DB_ROOT}\\\"\\n\",\n \"print(\\\"\\\\n✓ All file paths are valid\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4b80dc65\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== SQL Column Extraction Test ===\\n\",\n \"Tables: {'song', 'singer'}\\n\",\n \"Columns: {'song': {'singer_id', 'title'}, 'singer': {'id', 'name', 'country', 'age'}}\\n\",\n \"Has *: False\\n\",\n \"\\n\",\n \"=== Permission Check Test (Allow) ===\\n\",\n \"Allowed: True\\n\",\n \"Reason: All required columns are permitted\\n\",\n \"\\n\",\n \"=== Permission Check Test (Deny) ===\\n\",\n \"Allowed: False\\n\",\n \"Reason: Missing column permissions: song: singer_id; singer: age, country, id\\n\",\n \"Missing: {'song': {'singer_id'}, 'singer': {'id', 'country', 'age'}}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.2 Test SQL column extraction and permission checking\\n\",\n \"# Verified working, archived to simplify notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"test_sql = \\\"\\\"\\\"\\n\",\n \"SELECT singer.name, singer.age, song.title\\n\",\n \"FROM singer\\n\",\n \"JOIN song ON singer.id = song.singer_id\\n\",\n \"WHERE singer.country = 'USA'\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"print(\\\"=== SQL Column Extraction Test ===\\\")\\n\",\n \"info = extract_query_columns(test_sql)\\n\",\n \"print(f\\\"Tables: {info.tables}\\\")\\n\",\n \"print(f\\\"Columns: {info.columns}\\\")\\n\",\n \"print(f\\\"Has *: {info.has_star}\\\")\\n\",\n \"\\n\",\n \"# Test permission checking\\n\",\n \"policy_allow = {\\n\",\n \" 'singer': ['name', 'age', 'country', 'id'],\\n\",\n \" 'song': ['title', 'singer_id']\\n\",\n \"}\\n\",\n \"policy_deny = {\\n\",\n \" 'singer': ['name'], # Missing 'age', 'country', 'id'\\n\",\n \" 'song': ['title'] # Missing 'singer_id'\\n\",\n \"}\\n\",\n \"\\n\",\n \"print(\\\"\\\\n=== Permission Check Test (Allow) ===\\\")\\n\",\n \"result1 = check_column_permission(test_sql, policy_allow)\\n\",\n \"print(f\\\"Allowed: {result1.allowed}\\\")\\n\",\n \"print(f\\\"Reason: {result1.reason}\\\")\\n\",\n \"\\n\",\n \"print(\\\"\\\\n=== Permission Check Test (Deny) ===\\\")\\n\",\n \"result2 = check_column_permission(test_sql, policy_deny)\\n\",\n \"print(f\\\"Allowed: {result2.allowed}\\\")\\n\",\n \"print(f\\\"Reason: {result2.reason}\\\")\\n\",\n \"print(f\\\"Missing: {result2.missing_columns}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Column extraction/permission tests - verified\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 16,\n \"id\": \"0a018208\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Generator Initialized ===\\n\",\n \"Total BIRD queries: 1534\\n\",\n \"Databases with role assignments: 11\\n\",\n \"Databases with queries: 11\\n\",\n \"\\n\",\n \"Queries per database:\\n\",\n \" california_schools: 89\\n\",\n \" card_games: 191\\n\",\n \" codebase_community: 186\\n\",\n \" debit_card_specializing: 64\\n\",\n \" european_football_2: 129\\n\",\n \" financial: 106\\n\",\n \" formula_1: 174\\n\",\n \" student_club: 158\\n\",\n \" superhero: 129\\n\",\n \" thrombosis_prediction: 163\\n\",\n \" toxicology: 145\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 4.3 Initialize generator\\n\",\n \"generator = ColumnLevelRBACGenerator(\\n\",\n \" role_assignments_path=str(ROLE_ASSIGNMENTS_PATH),\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH),\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" project_root=str(project_root),\\n\",\n \" seed=42\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"=== Generator Initialized ===\\\")\\n\",\n \"print(f\\\"Total BIRD queries: {len(generator.bird_data)}\\\")\\n\",\n \"print(f\\\"Databases with role assignments: {len(generator.role_assignments.get('assignments', {}))}\\\")\\n\",\n \"print(f\\\"Databases with queries: {len(generator.queries_by_db)}\\\")\\n\",\n \"\\n\",\n \"# Show query counts per database\\n\",\n \"print(\\\"\\\\nQueries per database:\\\")\\n\",\n \"for db_id, queries in sorted(generator.queries_by_db.items()):\\n\",\n \" print(f\\\" {db_id}: {len(queries)}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"2a267246\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# [ARCHIVED] 4.4 Generate sample dataset (for format validation)\\n\",\n \"# Sample dataset used for debugging, production uses 4.5\\n\",\n \"\\n\",\n \"'''\\n\",\n \"print(\\\"=== Generating Sample Dataset ===\\\")\\n\",\n \"sample_stats = generator.generate_and_save(\\n\",\n \" output_path=str(project_root / 'outputs' / 'column_level_rbac_dataset_bird_sample.json'),\\n\",\n \" roles_per_db=1, # Use only 1 role per database\\n\",\n \" queries_per_role=3 # Use only 3 queries per role\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"\\\\\\\\nStatistics:\\\")\\n\",\n \"for k, v in sample_stats.items():\\n\",\n \" if k != 'by_database':\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Sample dataset generation - production uses 4.5\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4851fde0\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Data Format Validation ===\\n\",\n \"Total entries: 33\\n\",\n \"\\n\",\n \"--- Allowed Entry Example ---\\n\",\n \"db_id: toxicology\\n\",\n \"role: MolecularResearcher\\n\",\n \"policy: {\\\"molecule\\\": [\\\"molecule_id\\\", \\\"label\\\"], \\\"atom\\\": [\\\"atom_id\\\", \\\"molecule_id\\\", \\\"element\\\"], \\\"bond\\\": [\\\"bond...\\n\",\n \"input: What are the atom IDs of the bond TR000_2_5?...\\n\",\n \"output: SELECT T.atom_id FROM connected AS T WHERE T.bond_id = 'TR000_2_5'...\\n\",\n \"difficulty: simple\\n\",\n \"instruction length: 1887 chars\\n\",\n \"\\n\",\n \"--- Denied Entry Example ---\\n\",\n \"db_id: thrombosis_prediction\\n\",\n \"role: ClinicalResearcher\\n\",\n \"input: How old was the patient who had the highest hemoglobin count on the date of labo...\\n\",\n \"output: Sorry, I cannot answer.\\n\",\n \"missing_columns: {'patient': ['Diagnosis']}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.5-4.6 Validate generated data format & Show instruction example\\n\",\n \"# Data format verified, archived to simplify notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"sample_file = project_root / 'outputs' / 'column_level_rbac_dataset_bird_sample.json'\\n\",\n \"with open(sample_file, 'r') as f:\\n\",\n \" sample_data = json.load(f)\\n\",\n \"\\n\",\n \"print(\\\"=== Data Format Validation ===\\\")\\n\",\n \"print(f\\\"Total entries: {len(sample_data)}\\\")\\n\",\n \"\\n\",\n \"allowed_entry = next((e for e in sample_data if e['metadata']['permission'] == 'allowed'), None)\\n\",\n \"denied_entry = next((e for e in sample_data if e['metadata']['permission'] == 'denied'), None)\\n\",\n \"\\n\",\n \"if allowed_entry:\\n\",\n \" print(\\\"\\\\\\\\n--- Allowed Entry Example ---\\\")\\n\",\n \" print(f\\\"db_id: {allowed_entry['db_id']}\\\")\\n\",\n \" print(f\\\"role: {allowed_entry['role']}\\\")\\n\",\n \" print(f\\\"policy: {json.dumps(allowed_entry['policy'])[:100]}...\\\")\\n\",\n \" print(f\\\"input: {allowed_entry['input'][:80]}...\\\")\\n\",\n \" print(f\\\"output: {allowed_entry['output'][:80]}...\\\")\\n\",\n \"\\n\",\n \"if denied_entry:\\n\",\n \" print(\\\"\\\\\\\\n--- Denied Entry Example ---\\\")\\n\",\n \" print(f\\\"db_id: {denied_entry['db_id']}\\\")\\n\",\n \" print(f\\\"role: {denied_entry['role']}\\\")\\n\",\n \" print(f\\\"output: {denied_entry['output']}\\\")\\n\",\n \" print(f\\\"missing_columns: {denied_entry['metadata']['missing_columns']}\\\")\\n\",\n \"\\n\",\n \"# Show full instruction\\n\",\n \"print(\\\"\\\\\\\\n=== Full Instruction Example ===\\\")\\n\",\n \"if allowed_entry:\\n\",\n \" print(allowed_entry['instruction'][:2500])\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Data format validation - verified\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"c05e8787\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 4.5 Generate Full Column-Level RBAC Dataset\\n\",\n \"from datetime import datetime\\n\",\n \"\\n\",\n \"# Reload the modules to ensure we use the latest CTE fix\\n\",\n \"import importlib\\n\",\n \"import src.processors.column_extractor\\n\",\n \"import src.processors.column_permission_checker\\n\",\n \"import src.processors.column_level_rbac_generator\\n\",\n \"\\n\",\n \"importlib.reload(src.processors.column_extractor)\\n\",\n \"importlib.reload(src.processors.column_permission_checker)\\n\",\n \"importlib.reload(src.processors.column_level_rbac_generator)\\n\",\n \"\\n\",\n \"# Re-import with fresh code\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator\\n\",\n \"\\n\",\n \"# Re-create generator with fresh modules\\n\",\n \"generator = ColumnLevelRBACGenerator(\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" role_assignments_path=str(ROLE_ASSIGNMENTS_PATH),\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH)\\n\",\n \")\\n\",\n \"\\n\",\n \"# Output with date suffix\\n\",\n \"today = datetime.now().strftime('%Y%m%d')\\n\",\n \"output_path = project_root / 'outputs' / f'column_level_rbac_dataset_bird_{today}.json'\\n\",\n \"\\n\",\n \"print(\\\"=== Generating Full Column-Level RBAC Dataset ===\\\")\\n\",\n \"print(f\\\"Output: {output_path}\\\")\\n\",\n \"\\n\",\n \"full_stats = generator.generate_and_save(\\n\",\n \" output_path=str(output_path),\\n\",\n \" roles_per_db=None, # Use all roles (number varies per db based on LLM generation)\\n\",\n \" queries_per_role=None # Use all queries\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"\\\\nFull dataset statistics:\\\")\\n\",\n \"for k, v in full_stats.items():\\n\",\n \" if k == 'by_database':\\n\",\n \" print(f\\\"\\\\nPer-database distribution:\\\")\\n\",\n \" for db_id, counts in v.items():\\n\",\n \" print(f\\\" {db_id}: allowed={counts['allowed']}, denied={counts['denied']}\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" {k}: {v}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"2142ac6e\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Comparison with Table-Level Data Format ===\\n\",\n \"\\n\",\n \"--- Table-Level Entry Fields ---\\n\",\n \"['db_id', 'difficulty', 'input', 'instruction', 'metadata', 'output', 'role', 'tables']\\n\",\n \"\\n\",\n \"--- Column-Level Entry Fields ---\\n\",\n \"['db_id', 'difficulty', 'input', 'instruction', 'metadata', 'output', 'policy', 'role']\\n\",\n \"\\n\",\n \"Common fields: {'output', 'role', 'metadata', 'difficulty', 'db_id', 'input', 'instruction'}\\n\",\n \"Table-Level only: {'tables'}\\n\",\n \"Column-Level only: {'policy'}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.6 Compare with Table-Level format\\n\",\n \"# Format comparison completed, archived to simplify notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"print(\\\"=== Comparison with Table-Level Data Format ===\\\")\\n\",\n \"\\n\",\n \"table_level_file = project_root / 'data' / 'selected' / 'bird' / 'bird_dev_with_role_rbac.json'\\n\",\n \"if table_level_file.exists():\\n\",\n \" with open(table_level_file, 'r') as f:\\n\",\n \" table_level_data = json.load(f)\\n\",\n \" \\n\",\n \" print(\\\"\\\\\\\\n--- Table-Level Entry Fields ---\\\")\\n\",\n \" print(sorted(table_level_data[0].keys()))\\n\",\n \" \\n\",\n \" print(\\\"\\\\\\\\n--- Column-Level Entry Fields ---\\\") \\n\",\n \" print(sorted(sample_data[0].keys()))\\n\",\n \" \\n\",\n \" tl_keys = set(table_level_data[0].keys())\\n\",\n \" cl_keys = set(sample_data[0].keys())\\n\",\n \" \\n\",\n \" print(f\\\"\\\\\\\\nCommon fields: {tl_keys & cl_keys}\\\")\\n\",\n \" print(f\\\"Table-Level only: {tl_keys - cl_keys}\\\")\\n\",\n \" print(f\\\"Column-Level only: {cl_keys - tl_keys}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Table-level comparison - format verified compatible\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"7392ebc1\",\n \"metadata\": {},\n \"source\": [\n \"## 5. Role Generation Quality Assessment\\n\",\n \"\\n\",\n \"Automated quality checks for generated role files and RBAC datasets.\\n\",\n \"\\n\",\n \"### Quality Metrics\\n\",\n \"\\n\",\n \"| Metric | Healthy Range | Issue Description |\\n\",\n \"|--------|---------------|-------------------|\\n\",\n \"| **Deny Rate** | 5% - 90% | <5% too permissive, >90% too restrictive |\\n\",\n \"| **All-Allow Queries** | <50% | High value indicates poor role differentiation |\\n\",\n \"| **Role-Schema Similarity** | >0.6 | <0.6 indicates poor semantic alignment |\\n\",\n \"| **Policy Overlap** | <70% | >70% indicates redundant roles |\\n\",\n \"| **Coverage Diversity** | std >0.1 | Low std indicates roles have similar permissions |\\n\",\n \"\\n\",\n \"### Evaluation Pipeline\\n\",\n \"1. **Deny Rate Analysis**: Check permission distribution balance\\n\",\n \"2. **Semantic Quality**: Embedding-based role-schema alignment\\n\",\n \"3. **Policy Overlap**: Jaccard similarity to detect redundant roles\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"71f8f60f\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 5.1 Setup Quality Evaluator (force reload all modules)\\n\",\n \"import importlib\\n\",\n \"import sys\\n\",\n \"from pathlib import Path\\n\",\n \"import glob\\n\",\n \"\\n\",\n \"# Force reload the entire module tree\\n\",\n \"if 'src.role_evaluator.quality_metrics' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator.quality_metrics']\\n\",\n \"if 'src.role_evaluator.quality_visualizer' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator.quality_visualizer']\\n\",\n \"if 'src.role_evaluator' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator']\\n\",\n \"\\n\",\n \"from src.role_evaluator import RoleQualityEvaluator, RoleQualityVisualizer, print_quality_report\\n\",\n \"\\n\",\n \"# Configure paths\\n\",\n \"project_root = Path.cwd().parent if Path.cwd().name == 'notebooks' else Path.cwd()\\n\",\n \"\\n\",\n \"# Find most recent dataset and role assignments files\\n\",\n \"role_files = sorted(glob.glob(str(project_root / 'outputs' / 'column_level_role_assignments_bird_*.json')))\\n\",\n \"ROLE_ASSIGNMENTS_PATH = role_files[-1] if role_files else str(project_root / 'outputs' / 'column_level_role_assignments_bird.json')\\n\",\n \"\\n\",\n \"# Check for v2 role assignments (after regeneration)\\n\",\n \"role_files_v2 = sorted([f for f in glob.glob(str(project_root / 'outputs' / 'bird_column_level_rbac_assignments_*.json'))\\n\",\n \" if 'v2' in f])\\n\",\n \"if role_files_v2:\\n\",\n \" ROLE_ASSIGNMENTS_PATH = role_files_v2[-1]\\n\",\n \"\\n\",\n \"dataset_files = sorted([f for f in glob.glob(str(project_root / 'outputs' / 'column_level_rbac_dataset_bird_*.json')) \\n\",\n \" if 'metadata' not in f])\\n\",\n \"if not dataset_files:\\n\",\n \" raise FileNotFoundError(\\\"No RBAC dataset found in outputs/\\\")\\n\",\n \"DATASET_PATH = dataset_files[-1]\\n\",\n \"\\n\",\n \"SCHEMA_DIR = str(project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases')\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# CONFIGURABLE QUALITY THRESHOLDS\\n\",\n \"# Adjust based on dataset characteristics\\n\",\n \"# BIRD has larger DBs with more columns, so thresholds differ from Spider\\n\",\n \"# ============================================================\\n\",\n \"QUALITY_THRESHOLDS = {\\n\",\n \" \\\"deny_rate_min\\\": 5.0, # Warn if deny rate < this (roles too permissive)\\n\",\n \" \\\"coverage_max\\\": 0.85, # Warn if avg coverage > this (roles too broad)\\n\",\n \" \\\"coverage_std_min\\\": 0.065, # Warn if coverage std < this (low diversity)\\n\",\n \" \\\"max_overlap\\\": 0.80, # Warn if max overlap > this (redundant roles)\\n\",\n \"}\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EMBEDDING MODEL CONFIGURATION\\n\",\n \"# Backend auto-detected based on model name, or set explicitly\\n\",\n \"# ============================================================\\n\",\n \"# OpenAI models (requires OPENAI_API_KEY):\\n\",\n \"# - \\\"text-embedding-3-small\\\" (default, cost-effective)\\n\",\n \"# - \\\"text-embedding-3-large\\\" (higher accuracy)\\n\",\n \"# - \\\"text-embedding-ada-002\\\" (legacy)\\n\",\n \"# \\n\",\n \"# BAAI/fastembed models (local, no API key needed):\\n\",\n \"# - \\\"BAAI/bge-small-en-v1.5\\\" (fast, lightweight)\\n\",\n \"# - \\\"BAAI/bge-base-en-v1.5\\\" (balanced)\\n\",\n \"# - \\\"BAAI/bge-large-en-v1.5\\\" (best accuracy)\\n\",\n \"# ============================================================\\n\",\n \"# EMBED_MODEL = \\\"BAAI/bge-small-en-v1.5\\\"\\n\",\n \"EMBED_MODEL = \\\"text-embedding-3-small\\\"\\n\",\n \"EMBED_BACKEND = None # None = auto-detect, or \\\"openai\\\" / \\\"fastembed\\\"\\n\",\n \"\\n\",\n \"print(\\\"=== Quality Thresholds (Configurable for BIRD) ===\\\")\\n\",\n \"for k, v in QUALITY_THRESHOLDS.items():\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"print(f\\\" embed_model: {EMBED_MODEL}\\\")\\n\",\n \"print(f\\\" embed_backend: {EMBED_BACKEND or 'auto'}\\\")\\n\",\n \"\\n\",\n \"print(f\\\"\\\\nRole Assignments: {Path(ROLE_ASSIGNMENTS_PATH).name if ROLE_ASSIGNMENTS_PATH else 'Not found'}\\\")\\n\",\n \"print(f\\\"Dataset: {Path(DATASET_PATH).name if DATASET_PATH else 'Not found'}\\\")\\n\",\n \"print(f\\\"Schema Dir: {SCHEMA_DIR}\\\")\\n\",\n \"\\n\",\n \"if ROLE_ASSIGNMENTS_PATH and DATASET_PATH:\\n\",\n \" evaluator = RoleQualityEvaluator(\\n\",\n \" role_assignments_path=ROLE_ASSIGNMENTS_PATH,\\n\",\n \" dataset_path=DATASET_PATH,\\n\",\n \" schema_dir=SCHEMA_DIR,\\n\",\n \" embed_model=EMBED_MODEL,\\n\",\n \" embed_backend=EMBED_BACKEND,\\n\",\n \" thresholds=QUALITY_THRESHOLDS\\n\",\n \" )\\n\",\n \" print(\\\"\\\\n✓ Quality evaluator initialized with custom thresholds\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"\\\\n Missing files - generate roles and dataset first\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 74,\n \"id\": \"8135e2e3\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[embedding_utils] Using OpenAI embeddings (text-embedding-3-small) for 11 texts\\n\",\n \"[embedding_utils] Using OpenAI embeddings (text-embedding-3-small) for 47 texts\\n\",\n \"Overall: 11 databases, 53 roles, 7252 entries\\n\",\n \"Pass Rate: 100.0% (11/11 pass)\\n\",\n \"\\n\",\n \"Using Thresholds: deny_rate_min=5.0%, max_overlap=80%, coverage_std_min=0.065\\n\",\n \"\\n\",\n \"=== Deny Rate Analysis ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseDeny%AllAllow%AllDenyRolesStatus
0california_schools73.5%1.1%05OK
1card_games46.9%2.1%05OK
2codebase_community37.8%0.0%05OK
3debit_card_specializing54.7%0.0%06OK
4european_football_257.1%1.6%05OK
5financial70.6%0.0%05OK
6formula_144.7%8.7%04OK
7student_club49.9%1.3%05OK
8superhero49.1%0.0%05OK
9thrombosis_prediction33.7%2.5%04OK
10toxicology47.4%11.7%04OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Deny% AllAllow% AllDeny Roles Status\\n\",\n \"0 california_schools 73.5% 1.1% 0 5 OK\\n\",\n \"1 card_games 46.9% 2.1% 0 5 OK\\n\",\n \"2 codebase_community 37.8% 0.0% 0 5 OK\\n\",\n \"3 debit_card_specializing 54.7% 0.0% 0 6 OK\\n\",\n \"4 european_football_2 57.1% 1.6% 0 5 OK\\n\",\n \"5 financial 70.6% 0.0% 0 5 OK\\n\",\n \"6 formula_1 44.7% 8.7% 0 4 OK\\n\",\n \"7 student_club 49.9% 1.3% 0 5 OK\\n\",\n \"8 superhero 49.1% 0.0% 0 5 OK\\n\",\n \"9 thrombosis_prediction 33.7% 2.5% 0 4 OK\\n\",\n \"10 toxicology 47.4% 11.7% 0 4 OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Semantic Quality (Similarity: role-schema alignment, Coverage: column access, Diversity: coverage std) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseSimilarityCoverageDiversityStatus
0california_schools0.690234.8%0.0996OK
1card_games0.684350.0%0.2965OK
2codebase_community0.633260.6%0.2888OK
3debit_card_specializing0.626463.8%0.1299OK
4european_football_20.679931.3%0.0984OK
5financial0.641046.8%0.1288OK
6formula_10.659944.0%0.1480OK
7student_club0.678050.5%0.1701OK
8superhero0.683561.3%0.1895OK
9thrombosis_prediction0.660769.3%0.3798OK
10toxicology0.669869.7%0.1134OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Similarity Coverage Diversity Status\\n\",\n \"0 california_schools 0.6902 34.8% 0.0996 OK\\n\",\n \"1 card_games 0.6843 50.0% 0.2965 OK\\n\",\n \"2 codebase_community 0.6332 60.6% 0.2888 OK\\n\",\n \"3 debit_card_specializing 0.6264 63.8% 0.1299 OK\\n\",\n \"4 european_football_2 0.6799 31.3% 0.0984 OK\\n\",\n \"5 financial 0.6410 46.8% 0.1288 OK\\n\",\n \"6 formula_1 0.6599 44.0% 0.1480 OK\\n\",\n \"7 student_club 0.6780 50.5% 0.1701 OK\\n\",\n \"8 superhero 0.6835 61.3% 0.1895 OK\\n\",\n \"9 thrombosis_prediction 0.6607 69.3% 0.3798 OK\\n\",\n \"10 toxicology 0.6698 69.7% 0.1134 OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Policy Overlap Analysis ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseAvgOverlapMaxOverlapStatus
0california_schools30.7%57.1%OK
1card_games11.9%23.8%OK
2codebase_community28.0%57.8%OK
3debit_card_specializing47.0%65.0%OK
4european_football_214.4%23.8%OK
5financial21.5%37.0%OK
6formula_129.3%32.9%OK
7student_club30.2%45.0%OK
8superhero33.0%52.6%OK
9thrombosis_prediction18.1%38.5%OK
10toxicology53.7%66.7%OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database AvgOverlap MaxOverlap Status\\n\",\n \"0 california_schools 30.7% 57.1% OK\\n\",\n \"1 card_games 11.9% 23.8% OK\\n\",\n \"2 codebase_community 28.0% 57.8% OK\\n\",\n \"3 debit_card_specializing 47.0% 65.0% OK\\n\",\n \"4 european_football_2 14.4% 23.8% OK\\n\",\n \"5 financial 21.5% 37.0% OK\\n\",\n \"6 formula_1 29.3% 32.9% OK\\n\",\n \"7 student_club 30.2% 45.0% OK\\n\",\n \"8 superhero 33.0% 52.6% OK\\n\",\n \"9 thrombosis_prediction 18.1% 38.5% OK\\n\",\n \"10 toxicology 53.7% 66.7% OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n }\n ],\n \"source\": [\n \"# 5.2 Run Quality Evaluations and Display as DataFrame\\n\",\n \"import pandas as pd\\n\",\n \"import importlib\\n\",\n \"\\n\",\n \"# Force reload modules to use latest code\\n\",\n \"import src.role_evaluator.quality_metrics\\n\",\n \"import src.role_evaluator.quality_visualizer\\n\",\n \"importlib.reload(src.role_evaluator.quality_metrics)\\n\",\n \"importlib.reload(src.role_evaluator.quality_visualizer)\\n\",\n \"\\n\",\n \"from src.role_evaluator.quality_metrics import print_quality_report\\n\",\n \"\\n\",\n \"# Set display options for full content (no truncation)\\n\",\n \"pd.set_option('display.max_colwidth', None)\\n\",\n \"pd.set_option('display.max_rows', None)\\n\",\n \"pd.set_option('display.width', None)\\n\",\n \"\\n\",\n \"if 'evaluator' in dir():\\n\",\n \" report = evaluator.evaluate_all()\\n\",\n \" \\n\",\n \" # Summary\\n\",\n \" print(f\\\"Overall: {report.total_databases} databases, {report.total_roles} roles, {report.total_entries} entries\\\")\\n\",\n \" print(f\\\"Pass Rate: {report.pass_rate:.1%} ({report.total_databases - len(report.databases_with_issues)}/{report.total_databases} pass)\\\")\\n\",\n \" print(f\\\"\\\\nUsing Thresholds: deny_rate_min={QUALITY_THRESHOLDS['deny_rate_min']}%, \\\"\\n\",\n \" f\\\"max_overlap={QUALITY_THRESHOLDS['max_overlap']:.0%}, \\\"\\n\",\n \" f\\\"coverage_std_min={QUALITY_THRESHOLDS['coverage_std_min']}\\\\n\\\")\\n\",\n \" \\n\",\n \" # Deny Rate DataFrame - Full display\\n\",\n \" if report.deny_rate_metrics:\\n\",\n \" deny_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"Deny%\\\": f\\\"{m.deny_rate:.1f}%\\\",\\n\",\n \" \\\"AllAllow%\\\": f\\\"{m.all_allow_pct:.1f}%\\\",\\n\",\n \" \\\"AllDeny\\\": m.all_deny_queries,\\n\",\n \" \\\"Roles\\\": len(m.roles),\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.deny_rate_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"=== Deny Rate Analysis ===\\\")\\n\",\n \" display(deny_df)\\n\",\n \"\\n\",\n \" # Semantic Quality DataFrame \\n\",\n \" if report.semantic_metrics:\\n\",\n \" sem_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"Similarity\\\": f\\\"{m.avg_similarity:.4f}\\\",\\n\",\n \" \\\"Coverage\\\": f\\\"{m.avg_coverage:.1%}\\\",\\n\",\n \" \\\"Diversity\\\": f\\\"{m.coverage_std:.4f}\\\",\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.semantic_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Semantic Quality (Similarity: role-schema alignment, Coverage: column access, Diversity: coverage std) ===\\\")\\n\",\n \" display(sem_df)\\n\",\n \"\\n\",\n \" # Policy Overlap DataFrame\\n\",\n \" if report.overlap_metrics:\\n\",\n \" ovl_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"AvgOverlap\\\": f\\\"{m.avg_overlap:.1%}\\\",\\n\",\n \" \\\"MaxOverlap\\\": f\\\"{m.max_overlap:.1%}\\\",\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.overlap_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Policy Overlap Analysis ===\\\")\\n\",\n \" display(ovl_df)\\n\",\n \"else:\\n\",\n \" print(\\\" Evaluator not initialized\\\")\\n\",\n \"\\n\",\n \"pd.reset_option('display.max_colwidth')\\n\",\n \"pd.reset_option('display.max_rows')\\n\",\n \"pd.reset_option('display.width')\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 75,\n \"id\": \"89f843e7\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# # 5.3 Quality Dashboard Visualization\\n\",\n \"# import matplotlib.pyplot as plt\\n\",\n \"# from src.role_evaluator.quality_visualizer import RoleQualityVisualizer\\n\",\n \"\\n\",\n \"# visualizer = RoleQualityVisualizer(evaluator=evaluator, report=report)\\n\",\n \"# fig = visualizer.plot_quality_dashboard()\\n\",\n \"# plt.show()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"86eb26de\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 5.4 Semantic Alignment Visualization (Column-Level RBAC)\\n\",\n \"# Circle size = column coverage, Red triangles = SystemManager\\n\",\n \"import random\\n\",\n \"import math\\n\",\n \"import matplotlib.pyplot as plt\\n\",\n \"from matplotlib.colors import PowerNorm\\n\",\n \"from matplotlib import colormaps as cm\\n\",\n \"from collections import defaultdict\\n\",\n \"from matplotlib.lines import Line2D\\n\",\n \"import numpy as np\\n\",\n \"\\n\",\n \"sys.path.insert(0, str(project_root / \\\"plot\\\"))\\n\",\n \"from embedding_utils import cosine_similarity\\n\",\n \"\\n\",\n \"# Prepare records (recompute)\\n\",\n \"role_records = evaluator._prepare_role_records()\\n\",\n \"evaluator._compute_embeddings()\\n\",\n \"\\n\",\n \"# Build vis_records with is_system_manager\\n\",\n \"vis_records = []\\n\",\n \"for spec in role_records:\\n\",\n \" schema_emb = evaluator._schema_emb_dict.get(spec[\\\"schema_text\\\"])\\n\",\n \" role_emb = evaluator._role_emb_dict.get(spec[\\\"role_text\\\"])\\n\",\n \" \\n\",\n \" if schema_emb is not None and role_emb is not None:\\n\",\n \" raw_sim = cosine_similarity(role_emb, schema_emb)\\n\",\n \" similarity = max(0.0, min(1.0, (raw_sim + 1.0) / 2.0))\\n\",\n \" else:\\n\",\n \" similarity = 0.5\\n\",\n \" \\n\",\n \" total_cols = spec.get(\\\"total_columns\\\", 1)\\n\",\n \" accessible_cols = spec.get(\\\"accessible_columns\\\", 0)\\n\",\n \" col_coverage = accessible_cols / total_cols if total_cols > 0 else 0\\n\",\n \" \\n\",\n \" vis_records.append({\\n\",\n \" \\\"db_id\\\": spec[\\\"db_id\\\"],\\n\",\n \" \\\"role\\\": spec[\\\"role\\\"],\\n\",\n \" \\\"similarity\\\": similarity,\\n\",\n \" \\\"is_system_manager\\\": spec.get(\\\"is_system_manager\\\", False),\\n\",\n \" \\\"column_coverage\\\": col_coverage,\\n\",\n \" })\\n\",\n \"\\n\",\n \"sm_count = sum(1 for r in vis_records if r[\\\"is_system_manager\\\"])\\n\",\n \"print(f\\\"Total roles: {len(vis_records)}, SystemManager: {sm_count}\\\")\\n\",\n \"\\n\",\n \"# Plot function\\n\",\n \"def plot_semantic(records, output_path, title, dbs_per_panel=12):\\n\",\n \" db_to_entries = defaultdict(list)\\n\",\n \" sims = []\\n\",\n \" for rec in records:\\n\",\n \" sims.append(rec[\\\"similarity\\\"])\\n\",\n \" size = 90.0 + rec[\\\"column_coverage\\\"] * 220.0\\n\",\n \" db_to_entries[rec[\\\"db_id\\\"]].append({\\n\",\n \" \\\"sim\\\": rec[\\\"similarity\\\"], \\\"size\\\": size,\\n\",\n \" \\\"is_sm\\\": rec[\\\"is_system_manager\\\"],\\n\",\n \" })\\n\",\n \" \\n\",\n \" db_ids = sorted(db_to_entries.keys())\\n\",\n \" panels = [db_ids[i:i+dbs_per_panel] for i in range(0, len(db_ids), dbs_per_panel)]\\n\",\n \" \\n\",\n \" min_s, max_s = min(sims), max(sims)\\n\",\n \" if math.isclose(min_s, max_s): max_s = min_s + 1e-6\\n\",\n \" span = max_s - min_s\\n\",\n \" norm = PowerNorm(gamma=0.55, vmin=min_s, vmax=max_s)\\n\",\n \" cmap = cm[\\\"viridis\\\"]\\n\",\n \" \\n\",\n \" fig = plt.figure(figsize=(11, sum(0.35*len(p)+0.6 for p in panels)+2))\\n\",\n \" gs = fig.add_gridspec(len(panels), 1, height_ratios=[0.35*len(p)+0.6 for p in panels], hspace=0.18)\\n\",\n \" axes = []\\n\",\n \" \\n\",\n \" random.seed(42)\\n\",\n \" sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)\\n\",\n \" sm.set_array([])\\n\",\n \" \\n\",\n \" for pi, chunk in enumerate(panels):\\n\",\n \" ax = fig.add_subplot(gs[pi, 0])\\n\",\n \" axes.append(ax)\\n\",\n \" for ri, db in enumerate(chunk):\\n\",\n \" y = float(ri)\\n\",\n \" ax.axhline(y, color=\\\"#d0d0d0\\\", linestyle=\\\"--\\\", lw=0.9, zorder=0)\\n\",\n \" for e in db_to_entries[db]:\\n\",\n \" x = (e[\\\"sim\\\"] - min_s) / span + random.uniform(-0.012, 0.012)\\n\",\n \" if e[\\\"is_sm\\\"]:\\n\",\n \" ax.scatter(x, y, s=250, c=\\\"#d62728\\\", alpha=0.95,\\n\",\n \" edgecolors=\\\"#8c1c15\\\", lw=1.0, marker=\\\"^\\\", zorder=4)\\n\",\n \" else:\\n\",\n \" ax.scatter(x, y + random.uniform(-0.16, 0.16), s=e[\\\"size\\\"]*2.5,\\n\",\n \" c=[e[\\\"sim\\\"]], cmap=cmap, norm=norm, alpha=0.82,\\n\",\n \" edgecolors=\\\"#333\\\", lw=0.45, marker=\\\"o\\\")\\n\",\n \" ax.set_yticks(range(len(chunk)))\\n\",\n \" ax.set_yticklabels(chunk, fontsize=10, weight='bold')\\n\",\n \" ax.set_xlim(-0.05, 1.05)\\n\",\n \" ax.set_ylim(-0.6, len(chunk)-0.4)\\n\",\n \" ax.set_xticks(np.linspace(0, 1, 5))\\n\",\n \" ax.set_xticklabels([f\\\"{min_s + p*span:.2f}\\\" for p in np.linspace(0,1,5)], fontsize=9)\\n\",\n \" ax.grid(axis=\\\"x\\\", ls=\\\":\\\", lw=0.5, alpha=0.45)\\n\",\n \" \\n\",\n \" axes[-1].set_xlabel(\\\"Semantic similarity\\\", fontsize=12, weight='bold')\\n\",\n \" fig.suptitle(f\\\"{title}: Role-Schema Alignment\\\", fontsize=14, y=0.98, weight='bold')\\n\",\n \" cbar = fig.colorbar(sm, ax=axes, fraction=0.03, pad=0.015)\\n\",\n \" cbar.set_label(\\\"Similarity\\\", fontsize=10)\\n\",\n \" \\n\",\n \" legend = [\\n\",\n \" Line2D([0],[0], marker='^', color='w', markerfacecolor='#d62728',\\n\",\n \" markeredgecolor='#8c1c15', markersize=12, label='SystemManager'),\\n\",\n \" Line2D([0],[0], marker='o', color='w', markerfacecolor='#21918c',\\n\",\n \" markeredgecolor='#333', markersize=8, label='Other (size=col coverage)'),\\n\",\n \" ]\\n\",\n \" fig.legend(handles=legend, loc='upper right', fontsize=9)\\n\",\n \" plt.tight_layout(rect=[0,0,0.95,0.95])\\n\",\n \" fig.savefig(output_path, dpi=150, bbox_inches='tight')\\n\",\n \" plt.close(fig)\\n\",\n \" print(f\\\"Saved: {output_path}\\\")\\n\",\n \"\\n\",\n \"output_path = project_root / \\\"plot\\\" / \\\"column_level_rbac_semantic.png\\\"\\n\",\n \"plot_semantic(vis_records, output_path, \\\"Column-Level RBAC (BIRD)\\\")\\n\",\n \"from IPython.display import Image, display\\n\",\n \"display(Image(filename=str(output_path)))\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 13,\n \"id\": \"2dd807b4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Databases Requiring Review (1/11) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseDeny%AllAllow%CoverageCovStdMaxOverlapIssues
0california_schools63.1%5.6%50.8%0.05972.3%all-deny queries found (1) - SystemManager coverage broken; Low role diversity
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Deny% AllAllow% Coverage CovStd MaxOverlap \\\\\\n\",\n \"0 california_schools 63.1% 5.6% 50.8% 0.059 72.3% \\n\",\n \"\\n\",\n \" Issues \\n\",\n \"0 all-deny queries found (1) - SystemManager coverage broken; Low role diversity \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"Issue Thresholds:\\n\",\n \" - Deny% < 5%: roles too permissive\\n\",\n \" - Coverage > 85%: most roles have near-full access\\n\",\n \" - CovStd < 0.065: roles have similar coverage (low diversity)\\n\",\n \" - MaxOverlap >80%: redundant roles with similar policies\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 5.5 Export Problematic Databases as DataFrame\\n\",\n \"if report.databases_with_issues:\\n\",\n \" issues_data = []\\n\",\n \" for db_id in report.databases_with_issues:\\n\",\n \" row = {\\\"Database\\\": db_id}\\n\",\n \" \\n\",\n \" if db_id in report.deny_rate_metrics:\\n\",\n \" m = report.deny_rate_metrics[db_id]\\n\",\n \" row[\\\"Deny%\\\"] = f\\\"{m.deny_rate:.1f}%\\\"\\n\",\n \" row[\\\"AllAllow%\\\"] = f\\\"{m.all_allow_pct:.1f}%\\\"\\n\",\n \" \\n\",\n \" if db_id in report.semantic_metrics:\\n\",\n \" m = report.semantic_metrics[db_id]\\n\",\n \" row[\\\"Coverage\\\"] = f\\\"{m.avg_coverage:.1%}\\\" # Source of \\\"Most roles too permissive\\\" (>90%)\\n\",\n \" row[\\\"CovStd\\\"] = f\\\"{m.coverage_std:.3f}\\\" # Source of \\\"Low role diversity\\\" (<0.1)\\n\",\n \" \\n\",\n \" if db_id in report.overlap_metrics:\\n\",\n \" m = report.overlap_metrics[db_id]\\n\",\n \" row[\\\"MaxOverlap\\\"] = f\\\"{m.max_overlap:.1%}\\\" # Source of \\\"High max overlap\\\" (>70%)\\n\",\n \" \\n\",\n \" row[\\\"Issues\\\"] = \\\"; \\\".join(report.all_issues.get(db_id, []))\\n\",\n \" issues_data.append(row)\\n\",\n \" \\n\",\n \" issues_df = pd.DataFrame(issues_data)\\n\",\n \" print(f\\\"=== Databases Requiring Review ({len(issues_df)}/{report.total_databases}) ===\\\")\\n\",\n \" \\n\",\n \" # Display with full column width for Issues column\\n\",\n \" pd.set_option('display.max_colwidth', None)\\n\",\n \" pd.set_option('display.max_rows', None)\\n\",\n \" display(issues_df)\\n\",\n \" pd.reset_option('display.max_colwidth')\\n\",\n \" pd.reset_option('display.max_rows')\\n\",\n \" \\n\",\n \" print(\\\"\\\\nIssue Thresholds:\\\")\\n\",\n \" print(\\\" - Deny% < 5%: roles too permissive\\\")\\n\",\n \" print(\\\" - Coverage > 85%: most roles have near-full access\\\")\\n\",\n \" print(\\\" - CovStd < 0.065: roles have similar coverage (low diversity)\\\")\\n\",\n \" print(\\\" - MaxOverlap >80%: redundant roles with similar policies\\\")\\n\",\n \"\\n\",\n \"else:\\n\",\n \" print(\\\"[OK] All databases pass quality checks!\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"7586c455\",\n \"metadata\": {},\n \"source\": [\n \"## 6. Regenerate Roles for Problematic Databases\\n\",\n \"\\n\",\n \"Human-in-the-loop workflow for fixing quality issues:\\n\",\n \"\\n\",\n \"| Step | Cell | Description |\\n\",\n \"|------|------|-------------|\\n\",\n \"| 1 | 6.1 | Select database, view schema and current roles |\\n\",\n \"| 2 | 6.2 | Write regeneration hints (edit manually) |\\n\",\n \"| 3 | 6.3 | Execute regeneration with LLM |\\n\",\n \"| 4 | 6.4 | Preview and compare OLD vs NEW |\\n\",\n \"| 5 | 6.4.1 | Select & combine roles from OLD and NEW |\\n\",\n \"| 6 | 6.5 | Apply changes if satisfied |\\n\",\n \"| 7 | 6.6 | Regenerate RBAC Dataset with updated roles |\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 32,\n \"id\": \"70f25858\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"Database: formula_1\\n\",\n \"======================================================================\\n\",\n \"\\n\",\n \"=== Schema (13 tables, 94 columns) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
TableColumnTypePKFK
0circuitscircuitIdINTEGERYes
1circuitscircuitRefTEXT
2circuitsnameTEXT
3circuitslocationTEXT
4circuitscountryTEXT
..................
89resultsfastestLapINTEGER
90resultsrankINTEGER
91resultsfastestLapTimeTEXT
92resultsfastestLapSpeedTEXT
93resultsstatusIdINTEGERstatus.statusId
\\n\",\n \"

94 rows × 5 columns

\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Table Column Type PK FK\\n\",\n \"0 circuits circuitId INTEGER Yes \\n\",\n \"1 circuits circuitRef TEXT \\n\",\n \"2 circuits name TEXT \\n\",\n \"3 circuits location TEXT \\n\",\n \"4 circuits country TEXT \\n\",\n \".. ... ... ... ... ...\\n\",\n \"89 results fastestLap INTEGER \\n\",\n \"90 results rank INTEGER \\n\",\n \"91 results fastestLapTime TEXT \\n\",\n \"92 results fastestLapSpeed TEXT \\n\",\n \"93 results statusId INTEGER status.statusId\\n\",\n \"\\n\",\n \"[94 rows x 5 columns]\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Current Roles (5) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
RoleDescriptionTablesColumnsPolicy
0RaceAnalystAnalyzes race performance data including lap times, pit stops, and qualifying results965 (*)circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date, time]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]; status: [statusId, status]
1StandingsManagerManages championship standings and constructor/driver points calculations743 (*)constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; results: [resultId, raceId, driverId, constructorId, position, positionOrder, points]
2MediaCoordinatorProvides public information for media and fan engagement633 (*)circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, constructorRef, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [*]; races: [raceId, year, round, circuitId, name, date, time, url]; status: [statusId, status]
3DriverManagerManages driver information and personal details including date of birth432 (*)drivers: [*]; races: [raceId, year, round, name, date]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, statusId]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]
4SystemManagerFull administrative access for system maintenance and data integrity1394 (*)circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*]
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Role \\\\\\n\",\n \"0 RaceAnalyst \\n\",\n \"1 StandingsManager \\n\",\n \"2 MediaCoordinator \\n\",\n \"3 DriverManager \\n\",\n \"4 SystemManager \\n\",\n \"\\n\",\n \" Description \\\\\\n\",\n \"0 Analyzes race performance data including lap times, pit stops, and qualifying results \\n\",\n \"1 Manages championship standings and constructor/driver points calculations \\n\",\n \"2 Provides public information for media and fan engagement \\n\",\n \"3 Manages driver information and personal details including date of birth \\n\",\n \"4 Full administrative access for system maintenance and data integrity \\n\",\n \"\\n\",\n \" Tables Columns \\\\\\n\",\n \"0 9 65 (*) \\n\",\n \"1 7 43 (*) \\n\",\n \"2 6 33 (*) \\n\",\n \"3 4 32 (*) \\n\",\n \"4 13 94 (*) \\n\",\n \"\\n\",\n \" Policy \\n\",\n \"0 circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date, time]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]; status: [statusId, status] \\n\",\n \"1 constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; results: [resultId, raceId, driverId, constructorId, position, positionOrder, points] \\n\",\n \"2 circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, constructorRef, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [*]; races: [raceId, year, round, circuitId, name, date, time, url]; status: [statusId, status] \\n\",\n \"3 drivers: [*]; races: [raceId, year, round, name, date]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, statusId]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins] \\n\",\n \"4 circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*] \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Role x Table Matrix (column counts, * expanded) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
TablecircuitsconstructorResultsconstructorStandingsconstructorsdriverStandingsdriverslapTimespitStopsqualifyingracesresultsseasonsstatus
Role             
DriverManager0.0000000.0000000.0000000.0000007.0000009.0000000.0000000.0000000.0000005.00000011.0000000.0000000.000000
MediaCoordinator8.0000000.0000000.0000005.0000000.0000008.0000000.0000000.0000000.0000008.0000000.0000002.0000002.000000
RaceAnalyst6.0000000.0000000.0000004.0000000.0000007.0000006.0000007.0000009.0000007.00000017.0000000.0000002.000000
StandingsManager0.0000005.0000007.0000004.0000007.0000007.0000000.0000000.0000000.0000006.0000007.0000000.0000000.000000
SystemManager9.0000005.0000007.0000005.0000007.0000009.0000006.0000007.0000009.0000008.00000018.0000002.0000002.000000
\\n\"\n ],\n \"text/plain\": [\n \"\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"[SUMMARY] 1 database(s) selected: ['formula_1']\\n\",\n \"[NEXT] Edit hints in Cell 6.2, then run Cell 6.3\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.1 Select Database(s) & View Current State\\n\",\n \"# Supports single db (str) or multiple dbs (list)\\n\",\n \"\\n\",\n \"TARGET_DBS = [\\\"formula_1\\\"] # Single: \\\"toxicology\\\" or Multiple: [\\\"toxicology\\\", \\\"california_schools\\\"]\\n\",\n \"\\n\",\n \"# Normalize to list\\n\",\n \"if isinstance(TARGET_DBS, str):\\n\",\n \" TARGET_DBS = [TARGET_DBS]\\n\",\n \"\\n\",\n \"# Load current role assignments\\n\",\n \"with open(ROLE_ASSIGNMENTS_PATH, 'r') as f:\\n\",\n \" all_assignments = json.load(f)\\n\",\n \"\\n\",\n \"available_dbs = set(all_assignments.get('assignments', {}).keys())\\n\",\n \"valid_target_dbs = [db for db in TARGET_DBS if db in available_dbs]\\n\",\n \"invalid_dbs = [db for db in TARGET_DBS if db not in available_dbs]\\n\",\n \"\\n\",\n \"if invalid_dbs:\\n\",\n \" print(f\\\"[WARN] Databases not found: {invalid_dbs}\\\")\\n\",\n \" print(f\\\"Available: {sorted(available_dbs)}\\\\n\\\")\\n\",\n \"\\n\",\n \"# Store schemas for later use\\n\",\n \"target_schemas = {}\\n\",\n \"\\n\",\n \"for TARGET_DB in valid_target_dbs:\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"Database: {TARGET_DB}\\\")\\n\",\n \" print(f\\\"{'='*70}\\\")\\n\",\n \" \\n\",\n \" # --- Schema Summary ---\\n\",\n \" db_path = bird_db_dir / TARGET_DB / f\\\"{TARGET_DB}.sqlite\\\"\\n\",\n \" if db_path.exists():\\n\",\n \" target_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" target_schemas[TARGET_DB] = target_schema\\n\",\n \" \\n\",\n \" schema_rows = []\\n\",\n \" for table, info in target_schema.items():\\n\",\n \" for col in info['columns']:\\n\",\n \" schema_rows.append({\\n\",\n \" \\\"Table\\\": table,\\n\",\n \" \\\"Column\\\": col['name'],\\n\",\n \" \\\"Type\\\": col['type'],\\n\",\n \" \\\"PK\\\": \\\"Yes\\\" if col['pk'] else \\\"\\\",\\n\",\n \" \\\"FK\\\": col.get('fk', '') or \\\"\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" schema_df = pd.DataFrame(schema_rows)\\n\",\n \" print(f\\\"\\\\n=== Schema ({len(target_schema)} tables, {len(schema_df)} columns) ===\\\")\\n\",\n \" display(schema_df)\\n\",\n \" else:\\n\",\n \" print(f\\\"[ERROR] Database not found: {db_path}\\\")\\n\",\n \" target_schemas[TARGET_DB] = None\\n\",\n \" continue\\n\",\n \"\\n\",\n \" # --- Current Roles ---\\n\",\n \" if TARGET_DB in all_assignments.get('assignments', {}):\\n\",\n \" current_roles = all_assignments['assignments'][TARGET_DB]\\n\",\n \" \\n\",\n \" # Set display options for full content\\n\",\n \" pd.set_option('display.max_colwidth', None)\\n\",\n \" \\n\",\n \" roles_rows = []\\n\",\n \" for role_info in current_roles:\\n\",\n \" policy = role_info.get('policy', {})\\n\",\n \" total_access = count_policy_columns(policy, target_schema)\\n\",\n \" has_wildcard = has_wildcard_policy(policy)\\n\",\n \" cols_display = f\\\"{total_access}\\\" + (\\\" (*)\\\" if has_wildcard else \\\"\\\")\\n\",\n \" # Full policy string\\n\",\n \" policy_str = \\\"; \\\".join([\\n\",\n \" f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" \\n\",\n \" for t, c in policy.items()\\n\",\n \" ])\\n\",\n \" roles_rows.append({\\n\",\n \" \\\"Role\\\": role_info['role'],\\n\",\n \" \\\"Description\\\": role_info.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Columns\\\": cols_display,\\n\",\n \" \\\"Policy\\\": policy_str\\n\",\n \" })\\n\",\n \" \\n\",\n \" roles_df = pd.DataFrame(roles_rows)\\n\",\n \" print(f\\\"\\\\n=== Current Roles ({len(current_roles)}) ===\\\")\\n\",\n \" display(roles_df)\\n\",\n \" \\n\",\n \" pd.reset_option('display.max_colwidth')\\n\",\n \" \\n\",\n \" # Policy detail matrix\\n\",\n \" policy_rows = []\\n\",\n \" for role_info in current_roles:\\n\",\n \" policy = role_info.get('policy', {})\\n\",\n \" for table, cols in policy.items():\\n\",\n \" num_cols = count_policy_columns({table: cols}, target_schema)\\n\",\n \" policy_rows.append({\\n\",\n \" \\\"Role\\\": role_info['role'],\\n\",\n \" \\\"Table\\\": table,\\n\",\n \" \\\"NumCols\\\": num_cols\\n\",\n \" })\\n\",\n \" \\n\",\n \" if policy_rows:\\n\",\n \" policy_df = pd.DataFrame(policy_rows)\\n\",\n \" pivot = policy_df.pivot_table(index='Role', columns='Table', values='NumCols', fill_value=0)\\n\",\n \" print(\\\"\\\\n=== Role x Table Matrix (column counts, * expanded) ===\\\")\\n\",\n \" display(pivot.style.background_gradient(cmap='Blues', axis=None))\\n\",\n \" \\n\",\n \" # Quality issues\\n\",\n \" if 'report' in dir() and TARGET_DB in report.all_issues:\\n\",\n \" print(f\\\"\\\\n=== Quality Issues ===\\\")\\n\",\n \" issues = report.all_issues[TARGET_DB]\\n\",\n \" if TARGET_DB in report.deny_rate_metrics:\\n\",\n \" m = report.deny_rate_metrics[TARGET_DB]\\n\",\n \" issues_df = pd.DataFrame([{\\n\",\n \" \\\"Deny Rate\\\": f\\\"{m.deny_rate:.1f}%\\\",\\n\",\n \" \\\"All-Allow %\\\": f\\\"{m.all_allow_pct:.1f}%\\\",\\n\",\n \" \\\"Issues\\\": \\\"; \\\".join(issues)\\n\",\n \" }])\\n\",\n \" display(issues_df)\\n\",\n \" else:\\n\",\n \" print(f\\\"[ERROR] No roles found for {TARGET_DB}\\\")\\n\",\n \"\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"[SUMMARY] {len(valid_target_dbs)} database(s) selected: {valid_target_dbs}\\\")\\n\",\n \" print(\\\"[NEXT] Edit hints in Cell 6.2, then run Cell 6.3\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[INFO] No databases selected. Edit TARGET_DBS above and re-run.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 34,\n \"id\": \"f8416bc4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Applying shared hint to 1 database(s) ===\\n\",\n \"\\n\",\n \" ✓ formula_1: 13 tables, 94 columns\\n\",\n \"\\n\",\n \"[NEXT] Run Cell 6.3 to regenerate all 1 database(s)\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.2 Write Regeneration Hints (Human-in-the-Loop)\\n\",\n \"# Write ONE shared hint for all selected databases (they have similar issues)\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EDIT HERE: Shared problem description for all selected DBs\\n\",\n \"# Supports {db}, {num_tables}, {num_cols} placeholders\\n\",\n \"# ============================================================\\n\",\n \"# PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"# [PROBLEM]\\n\",\n \"# Low deny rate - almost all queries are allowed by all roles (roles too permissive)\\n\",\n \"# Low diversity - all roles have similar access patterns (coverage_std too low)\\n\",\n \"\\n\",\n \"\\n\",\n \"# [ROOT CAUSE]\\n\",\n \"# - Most roles can access most/all columns, so very few queries get denied\\n\",\n \"# - This defeats the purpose of RBAC - no meaningful access control\\n\",\n \"\\n\",\n \"# [DIRECTION]\\n\",\n \"# - Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"# - Create restrictive roles that only access specific subsets of data\\n\",\n \"# - Each role should have a clear, limited scope\\n\",\n \"# - Some roles should be restricted to fewer tables\\n\",\n \"# - Do not frequently giving non-admin roles \\\"*\\\" (all columns) access\\n\",\n \"# - Create clear functional boundaries between roles\\n\",\n \"# \\\"\\\"\\\"\\n\",\n \"\\n\",\n \"# All-denied cases - even SystemManager role cannot access some columns\\n\",\n \"# - Ensure SystemManager role has full access to all tables and columns\\n\",\n \"\\n\",\n \"\\n\",\n \"PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"[PROBLEM]\\n\",\n \"Low semantic alignment - roles do not align well with schema\\n\",\n \"All-denied cases - even SystemManager role cannot access some columns\\n\",\n \"\\n\",\n \"[ROOT CAUSE]\\n\",\n \"- This defeats the purpose of RBAC - no meaningful access control\\n\",\n \"\\n\",\n \"[DIRECTION]\\n\",\n \"- Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"- Ensure SystemManager role has full access to all tables and columns\\n\",\n \"- Review other roles to ensure they align with specific functional areas\\n\",\n \"- Each role should have a clear, limited scope\\n\",\n \"- Create meaningful semantic role names and descriptions that reflect their access patterns\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"# PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"# [PROBLEM]\\n\",\n \"# Low diversity - all roles have similar access patterns (coverage_std too low)\\n\",\n \"\\n\",\n \"# [ROOT CAUSE]\\n\",\n \"# - This defeats the purpose of RBAC - no meaningful access control differentiation\\n\",\n \"\\n\",\n \"# [DIRECTION]\\n\",\n \"# - Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"# - Create restrictive roles that only access specific subsets of data\\n\",\n \"# - Each role should have a clear, limited scope\\n\",\n \"# - Some roles should be restricted to fewer tables\\n\",\n \"# - Do not frequently giving non-admin roles \\\"*\\\" (all columns) access\\n\",\n \"# - Create clear functional boundaries between roles\\n\",\n \"# \\\"\\\"\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# Auto-apply to all selected databases (no need to edit below)\\n\",\n \"# ============================================================\\n\",\n \"REGENERATION_HINTS = {}\\n\",\n \"\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"=== Applying shared hint to {len(valid_target_dbs)} database(s) ===\\\\n\\\")\\n\",\n \" for db in valid_target_dbs:\\n\",\n \" schema = target_schemas.get(db, {})\\n\",\n \" num_tables = len(schema)\\n\",\n \" num_cols = sum(len(t['columns']) for t in schema.values())\\n\",\n \" \\n\",\n \" # Fill placeholders\\n\",\n \" REGENERATION_HINTS[db] = PROBLEM_TO_FIX.format(\\n\",\n \" db=db, num_tables=num_tables, num_cols=num_cols\\n\",\n \" )\\n\",\n \" print(f\\\" ✓ {db}: {num_tables} tables, {num_cols} columns\\\")\\n\",\n \"\\n\",\n \" print(f\\\"\\\\n[NEXT] Run Cell 6.3 to regenerate all {len(valid_target_dbs)} database(s)\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[INFO] No databases selected. Run Cell 6.1 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 68,\n \"id\": \"91109a7c\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Regenerating roles for 1 database(s)...\\n\",\n \"============================================================\\n\",\n \"\\n\",\n \"[formula_1] Generating...\\n\",\n \" ✓ 5 roles (5 valid)\\n\",\n \"\\n\",\n \"============================================================\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseStatusRolesValidTokens
0formula_1success553058
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Status Roles Valid Tokens\\n\",\n \"0 formula_1 success 5 5 3058\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"[OK] All databases regenerated. Run Cell 6.4 to preview.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.3 Execute Regeneration with Hints (supports multiple databases)\\n\",\n \"\\n\",\n \"def regenerate_single_database(db_name: str, hint: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Regenerate roles for a single database with guidance hints.\\\"\\\"\\\"\\n\",\n \" db_path = bird_db_dir / db_name / f\\\"{db_name}.sqlite\\\"\\n\",\n \" \\n\",\n \" if not db_path.exists():\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": \\\"Database not found\\\"}\\n\",\n \" \\n\",\n \" try:\\n\",\n \" db_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" db_schema_text = format_schema_for_prompt(db_schema, db_name)\\n\",\n \" \\n\",\n \" enhanced_system_prompt = f\\\"{COLUMN_LEVEL_SYSTEM_PROMPT}\\\\n\\\\n[OPTIMIZATION GUIDANCE]\\\\n{hint}\\\"\\n\",\n \" user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=db_schema_text)\\n\",\n \" \\n\",\n \" response = oracle.query(\\n\",\n \" prompt_sys=enhanced_system_prompt,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3,\\n\",\n \" top_p=0.9,\\n\",\n \" max_completion_tokens=DEFAULT_MAX_TOKENS\\n\",\n \" )\\n\",\n \" \\n\",\n \" llm_response = response['answer']\\n\",\n \" usage = response.get('usage', {})\\n\",\n \" roles = parse_column_level_roles(llm_response)\\n\",\n \" \\n\",\n \" if not roles:\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"parse_error\\\", \\n\",\n \" \\\"error\\\": \\\"Failed to parse LLM response\\\", \\\"raw_response\\\": llm_response[:500]}\\n\",\n \" \\n\",\n \" validation = validate_roles_against_schema(roles, str(db_path))\\n\",\n \" assignments = [{\\\"role\\\": r[\\\"role\\\"], \\\"description\\\": r.get(\\\"description\\\", \\\"\\\"), \\n\",\n \" \\\"policy\\\": r.get(\\\"columns\\\", {})} for r in roles]\\n\",\n \" \\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"success\\\", \\\"roles_count\\\": len(assignments),\\n\",\n \" \\\"valid_roles\\\": validation['valid_roles'], \\\"all_valid\\\": validation['all_valid'],\\n\",\n \" \\\"assignments\\\": assignments, \\\"usage\\\": usage, \\\"raw_response\\\": llm_response}\\n\",\n \" except Exception as e:\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": str(e)}\\n\",\n \"\\n\",\n \"# Execute for all target databases\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"Regenerating roles for {len(valid_target_dbs)} database(s)...\\\")\\n\",\n \" print(\\\"=\\\"*60)\\n\",\n \"\\n\",\n \" regenerated_results = {} # Store all results\\n\",\n \" all_success = True\\n\",\n \"\\n\",\n \" for db_name in valid_target_dbs:\\n\",\n \" hint = REGENERATION_HINTS.get(db_name, PROBLEM_TO_FIX)\\n\",\n \" print(f\\\"\\\\n[{db_name}] Generating...\\\")\\n\",\n \" \\n\",\n \" result = regenerate_single_database(db_name, hint)\\n\",\n \" regenerated_results[db_name] = result\\n\",\n \" \\n\",\n \" if result[\\\"status\\\"] == \\\"success\\\":\\n\",\n \" print(f\\\" ✓ {result['roles_count']} roles ({result['valid_roles']} valid)\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" ✗ {result.get('error', result['status'])}\\\")\\n\",\n \" all_success = False\\n\",\n \"\\n\",\n \" # Summary table\\n\",\n \" print(\\\"\\\\n\\\" + \\\"=\\\"*60)\\n\",\n \" result_df = pd.DataFrame([{\\n\",\n \" \\\"Database\\\": r[\\\"database\\\"],\\n\",\n \" \\\"Status\\\": r[\\\"status\\\"],\\n\",\n \" \\\"Roles\\\": r.get(\\\"roles_count\\\", \\\"N/A\\\"),\\n\",\n \" \\\"Valid\\\": r.get(\\\"valid_roles\\\", \\\"N/A\\\"),\\n\",\n \" \\\"Tokens\\\": r.get(\\\"usage\\\", {}).get(\\\"total_tokens\\\", \\\"N/A\\\")\\n\",\n \" } for r in regenerated_results.values()])\\n\",\n \" display(result_df)\\n\",\n \"\\n\",\n \" if all_success:\\n\",\n \" print(\\\"\\\\n[OK] All databases regenerated. Run Cell 6.4 to preview.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"\\\\n[WARN] Some databases failed. Check errors above.\\\")\\n\",\n \"else:\\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"[INFO] No databases selected. Run Cell 6.1 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 69,\n \"id\": \"a2b0ba98\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"Database: formula_1\\n\",\n \"======================================================================\\n\",\n \"\\n\",\n \"=== NEW Roles (5) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
RoleDescriptionTablesColsPolicy
0SystemManagerFull administrative access for system maintenance and data management1394 (*)circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*]
1RaceAnalystAnalyzes race performance data including lap times, pit stops, and qualifying results861circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; lapTimes: [raceId, driverId, lap, position, time, milliseconds]; pitStops: [raceId, driverId, stop, lap, time, duration, milliseconds]; qualifying: [qualifyId, raceId, driverId, constructorId, number, position, q1, q2, q3]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]
2StandingsManagerManages and monitors championship standings for drivers and constructors742constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, name, date]; constructorResults: [constructorResultsId, raceId, constructorId, points, status]; constructorStandings: [constructorStandingsId, raceId, constructorId, points, position, positionText, wins]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, points, position, positionText, statusId]
3PublicRelationsAccesses public information about circuits, drivers, constructors, and race schedules631circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [year, url]; races: [raceId, year, round, circuitId, name, date, url]; status: [statusId, status]
4DriverManagerManages driver information and personal details including date of birth432drivers: [driverId, driverRef, number, code, forename, surname, dob, nationality]; races: [raceId, year, round, name, date]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionText, positionOrder, points, laps, statusId]
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Role \\\\\\n\",\n \"0 SystemManager \\n\",\n \"1 RaceAnalyst \\n\",\n \"2 StandingsManager \\n\",\n \"3 PublicRelations \\n\",\n \"4 DriverManager \\n\",\n \"\\n\",\n \" Description \\\\\\n\",\n \"0 Full administrative access for system maintenance and data management \\n\",\n \"1 Analyzes race performance data including lap times, pit stops, and qualifying results \\n\",\n \"2 Manages and monitors championship standings for drivers and constructors \\n\",\n \"3 Accesses public information about circuits, drivers, constructors, and race schedules \\n\",\n \"4 Manages driver information and personal details including date of birth \\n\",\n \"\\n\",\n \" Tables Cols \\\\\\n\",\n \"0 13 94 (*) \\n\",\n \"1 8 61 \\n\",\n \"2 7 42 \\n\",\n \"3 6 31 \\n\",\n \"4 4 32 \\n\",\n \"\\n\",\n \" Policy \\n\",\n \"0 circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*] \\n\",\n \"1 circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; lapTimes: [raceId, driverId, lap, position, time, milliseconds]; pitStops: [raceId, driverId, stop, lap, time, duration, milliseconds]; qualifying: [qualifyId, raceId, driverId, constructorId, number, position, q1, q2, q3]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId] \\n\",\n \"2 constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, name, date]; constructorResults: [constructorResultsId, raceId, constructorId, points, status]; constructorStandings: [constructorStandingsId, raceId, constructorId, points, position, positionText, wins]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, points, position, positionText, statusId] \\n\",\n \"3 circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [year, url]; races: [raceId, year, round, circuitId, name, date, url]; status: [statusId, status] \\n\",\n \"4 drivers: [driverId, driverRef, number, code, forename, surname, dob, nationality]; races: [raceId, year, round, name, date]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionText, positionOrder, points, laps, statusId] \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Quality Comparison ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
MetricOLDNEWThresholdStatus
0Roles55NaNNaN
1Avg Coverage65.5%55.3%<85%OK
2Coverage Std0.1830.251>0.065OK
3Max Overlap87.3%57.4%<80%OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Metric OLD NEW Threshold Status\\n\",\n \"0 Roles 5 5 NaN NaN\\n\",\n \"1 Avg Coverage 65.5% 55.3% <85% OK\\n\",\n \"2 Coverage Std 0.183 0.251 >0.065 OK\\n\",\n \"3 Max Overlap 87.3% 57.4% <80% OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[OK] formula_1: All quality checks passed\\n\",\n \"\\n\",\n \"======================================================================\\n\",\n \"[DECISION] Satisfied? Run Cell 6.5 to apply. Otherwise edit Cell 6.2 and re-run 6.3.\\n\",\n \"[TIP] Use Cell 6.4.1 to select specific roles from OLD/NEW\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.4 Preview Regenerated Roles (Compare OLD vs NEW + Quality Check)\\n\",\n \"# Supports multiple databases\\n\",\n \"import numpy as np\\n\",\n \"from src.role_evaluator.quality_metrics import RoleQualityEvaluator\\n\",\n \"\\n\",\n \"pd.set_option('display.max_colwidth', None)\\n\",\n \"pd.set_option('display.max_rows', None)\\n\",\n \"pd.set_option('display.width', None)\\n\",\n \"\\n\",\n \"if 'regenerated_results' in dir() and regenerated_results:\\n\",\n \" for db_name, regen_result in regenerated_results.items():\\n\",\n \" if regen_result[\\\"status\\\"] != \\\"success\\\":\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"[SKIP] {db_name}: {regen_result.get('error', 'failed')}\\\")\\n\",\n \" continue\\n\",\n \" \\n\",\n \" regenerated_assignments = regen_result[\\\"assignments\\\"]\\n\",\n \" target_schema = target_schemas.get(db_name)\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"Database: {db_name}\\\")\\n\",\n \" print(f\\\"{'='*70}\\\")\\n\",\n \" \\n\",\n \" # --- NEW Role Summary ---\\n\",\n \" new_summary = []\\n\",\n \" for r in regenerated_assignments:\\n\",\n \" policy = r.get('policy', {})\\n\",\n \" total_cols = count_policy_columns(policy, target_schema)\\n\",\n \" has_wc = has_wildcard_policy(policy)\\n\",\n \" cols_display = f\\\"{total_cols}\\\" + (\\\" (*)\\\" if has_wc else \\\"\\\")\\n\",\n \" policy_str = \\\"; \\\".join([\\n\",\n \" f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" \\n\",\n \" for t, c in policy.items()\\n\",\n \" ])\\n\",\n \" new_summary.append({\\n\",\n \" \\\"Role\\\": r['role'],\\n\",\n \" \\\"Description\\\": r.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Cols\\\": cols_display,\\n\",\n \" \\\"Policy\\\": policy_str\\n\",\n \" })\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n=== NEW Roles ({len(regenerated_assignments)}) ===\\\")\\n\",\n \" display(pd.DataFrame(new_summary))\\n\",\n \" \\n\",\n \" # --- Quality Metrics ---\\n\",\n \" if target_schema:\\n\",\n \" total_schema_cols = sum(len(t['columns']) for t in target_schema.values())\\n\",\n \" else:\\n\",\n \" total_schema_cols = 10\\n\",\n \" \\n\",\n \" # NEW metrics\\n\",\n \" new_coverages = [count_policy_columns(r.get('policy', {}), target_schema) / total_schema_cols \\n\",\n \" for r in regenerated_assignments]\\n\",\n \" new_avg_cov = np.mean(new_coverages)\\n\",\n \" new_cov_std = np.std(new_coverages)\\n\",\n \" \\n\",\n \" new_max_overlap = 0.0\\n\",\n \" non_admin_new = [r for r in regenerated_assignments if 'admin' not in r['role'].lower()]\\n\",\n \" for i, r1 in enumerate(non_admin_new):\\n\",\n \" set1 = RoleQualityEvaluator.policy_to_column_set(r1.get('policy', {}))\\n\",\n \" for r2 in non_admin_new[i+1:]:\\n\",\n \" set2 = RoleQualityEvaluator.policy_to_column_set(r2.get('policy', {}))\\n\",\n \" new_max_overlap = max(new_max_overlap, RoleQualityEvaluator.jaccard_similarity(set1, set2))\\n\",\n \" \\n\",\n \" # OLD metrics\\n\",\n \" old_roles = all_assignments.get('assignments', {}).get(db_name, [])\\n\",\n \" if old_roles:\\n\",\n \" old_coverages = [count_policy_columns(r.get('policy', {}), target_schema) / total_schema_cols \\n\",\n \" for r in old_roles]\\n\",\n \" old_avg_cov = np.mean(old_coverages)\\n\",\n \" old_cov_std = np.std(old_coverages)\\n\",\n \" \\n\",\n \" old_max_overlap = 0.0\\n\",\n \" non_admin_old = [r for r in old_roles if 'admin' not in r['role'].lower()]\\n\",\n \" for i, r1 in enumerate(non_admin_old):\\n\",\n \" set1 = RoleQualityEvaluator.policy_to_column_set(r1.get('policy', {}))\\n\",\n \" for r2 in non_admin_old[i+1:]:\\n\",\n \" set2 = RoleQualityEvaluator.policy_to_column_set(r2.get('policy', {}))\\n\",\n \" old_max_overlap = max(old_max_overlap, RoleQualityEvaluator.jaccard_similarity(set1, set2))\\n\",\n \" else:\\n\",\n \" old_avg_cov, old_cov_std, old_max_overlap = 0, 0, 0\\n\",\n \" \\n\",\n \" # Comparison table (using QUALITY_THRESHOLDS from Cell 5.1)\\n\",\n \" def status(metric, val):\\n\",\n \" if metric == \\\"Coverage\\\": \\n\",\n \" return \\\"WARN\\\" if val > QUALITY_THRESHOLDS.get(\\\"coverage_max\\\", 0.90) else \\\"OK\\\"\\n\",\n \" if metric == \\\"CovStd\\\": \\n\",\n \" return \\\"WARN\\\" if val < QUALITY_THRESHOLDS.get(\\\"coverage_std_min\\\", 0.08) else \\\"OK\\\"\\n\",\n \" if metric == \\\"MaxOverlap\\\": \\n\",\n \" return \\\"WARN\\\" if val > QUALITY_THRESHOLDS.get(\\\"max_overlap\\\", 0.80) else \\\"OK\\\"\\n\",\n \" return \\\"OK\\\"\\n\",\n \" \\n\",\n \" quality_df = pd.DataFrame([\\n\",\n \" {\\\"Metric\\\": \\\"Roles\\\", \\\"OLD\\\": len(old_roles), \\\"NEW\\\": len(regenerated_assignments)},\\n\",\n \" {\\\"Metric\\\": \\\"Avg Coverage\\\", \\\"OLD\\\": f\\\"{old_avg_cov:.1%}\\\", \\\"NEW\\\": f\\\"{new_avg_cov:.1%}\\\", \\n\",\n \" \\\"Threshold\\\": f\\\"<{QUALITY_THRESHOLDS.get('coverage_max', 0.90):.0%}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"Coverage\\\", new_avg_cov)},\\n\",\n \" {\\\"Metric\\\": \\\"Coverage Std\\\", \\\"OLD\\\": f\\\"{old_cov_std:.3f}\\\", \\\"NEW\\\": f\\\"{new_cov_std:.3f}\\\",\\n\",\n \" \\\"Threshold\\\": f\\\">{QUALITY_THRESHOLDS.get('coverage_std_min', 0.08)}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"CovStd\\\", new_cov_std)},\\n\",\n \" {\\\"Metric\\\": \\\"Max Overlap\\\", \\\"OLD\\\": f\\\"{old_max_overlap:.1%}\\\", \\\"NEW\\\": f\\\"{new_max_overlap:.1%}\\\",\\n\",\n \" \\\"Threshold\\\": f\\\"<{QUALITY_THRESHOLDS.get('max_overlap', 0.80):.0%}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"MaxOverlap\\\", new_max_overlap)},\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Quality Comparison ===\\\")\\n\",\n \" display(quality_df)\\n\",\n \" \\n\",\n \" warn_count = quality_df['Status'].eq('WARN').sum() if 'Status' in quality_df.columns else 0\\n\",\n \" if warn_count == 0:\\n\",\n \" print(f\\\"[OK] {db_name}: All quality checks passed\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\"[WARN] {db_name}: {warn_count} issue(s)\\\")\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(\\\"[DECISION] Satisfied? Run Cell 6.5 to apply. Otherwise edit Cell 6.2 and re-run 6.3.\\\")\\n\",\n \" print(\\\"[TIP] Use Cell 6.4.1 to select specific roles from OLD/NEW\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[WARN] No regenerated results. Run Cell 6.3 first.\\\")\\n\",\n \"\\n\",\n \"pd.reset_option('display.max_colwidth')\\n\",\n \"pd.reset_option('display.max_rows')\\n\",\n \"pd.reset_option('display.width')\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 70,\n \"id\": \"f003a014\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Role Selection Summary ===\\n\",\n \"\\n\",\n \"============================================================\\n\",\n \"Database: formula_1\\n\",\n \" From OLD (0): (none)\\n\",\n \" From NEW (4): ['SystemManager', 'RaceAnalyst', 'PublicRelations', 'DriverManager']\\n\",\n \" Combined: 4 roles\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
SourceRoleDescriptionTablesPolicy
0NEWSystemManagerFull administrative access for system maintena...13circuits: [*]; constructors: [*]; drivers: [*]...
1NEWRaceAnalystAnalyzes race performance data including lap t...8circuits: [circuitId, name, location, country,...
2NEWPublicRelationsAccesses public information about circuits, dr...6circuits: [circuitId, name, location, country,...
3NEWDriverManagerManages driver information and personal detail...4drivers: [driverId, driverRef, number, code, f...
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Source Role Description \\\\\\n\",\n \"0 NEW SystemManager Full administrative access for system maintena... \\n\",\n \"1 NEW RaceAnalyst Analyzes race performance data including lap t... \\n\",\n \"2 NEW PublicRelations Accesses public information about circuits, dr... \\n\",\n \"3 NEW DriverManager Manages driver information and personal detail... \\n\",\n \"\\n\",\n \" Tables Policy \\n\",\n \"0 13 circuits: [*]; constructors: [*]; drivers: [*]... \\n\",\n \"1 8 circuits: [circuitId, name, location, country,... \\n\",\n \"2 6 circuits: [circuitId, name, location, country,... \\n\",\n \"3 4 drivers: [driverId, driverRef, number, code, f... \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"============================================================\\n\",\n \"[NEXT] Run Cell 6.5 to apply combined role sets\\n\",\n \"[TIP] Edit ROLE_SELECTION above to customize, then re-run this cell\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.4.1 Select & Combine Roles from OLD and NEW\\n\",\n \"# Human expert picks best roles from both versions to create final role set\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EDIT HERE: Specify which roles to keep from each version\\n\",\n \"# Format: {\\\"db_name\\\": {\\\"old\\\": [role_names], \\\"new\\\": [role_names]}}\\n\",\n \"# Leave empty [] to skip a version, or use [\\\"*\\\"] to keep all from that version\\n\",\n \"# ============================================================\\n\",\n \"ROLE_SELECTION = {\\n\",\n \" \\\"formula_1\\\": {\\n\",\n \" \\\"old\\\": [], # e.g., [\\\"DataAnalyst\\\", \\\"Researcher\\\"]\\n\",\n \" \\\"new\\\": [\\\"SystemManager\\\", \\\"RaceAnalyst\\\", \\\"PublicRelations\\\", \\\"DriverManager\\\"], # keep all new roles\\n\",\n \" },\\n\",\n \" # \\\"financial\\\": {\\n\",\n \" # \\\"old\\\": [],\\n\",\n \" # \\\"new\\\": [\\\"*\\\"],\\n\",\n \" # },\\n\",\n \"}\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# Process selections and create combined role sets\\n\",\n \"# ============================================================\\n\",\n \"combined_results = {}\\n\",\n \"\\n\",\n \"if 'regenerated_results' in dir() and regenerated_results:\\n\",\n \" print(\\\"=== Role Selection Summary ===\\\\n\\\")\\n\",\n \" \\n\",\n \" for db_name in valid_target_dbs:\\n\",\n \" selection = ROLE_SELECTION.get(db_name, {\\\"old\\\": [], \\\"new\\\": [\\\"*\\\"]})\\n\",\n \" old_keep = selection.get(\\\"old\\\", [])\\n\",\n \" new_keep = selection.get(\\\"new\\\", [\\\"*\\\"])\\n\",\n \" \\n\",\n \" # Get OLD roles\\n\",\n \" old_roles = all_assignments.get('assignments', {}).get(db_name, [])\\n\",\n \" old_role_dict = {r['role']: r for r in old_roles}\\n\",\n \" \\n\",\n \" # Get NEW roles\\n\",\n \" regen_result = regenerated_results.get(db_name, {})\\n\",\n \" if regen_result.get(\\\"status\\\") != \\\"success\\\":\\n\",\n \" print(f\\\"[SKIP] {db_name}: regeneration failed\\\")\\n\",\n \" continue\\n\",\n \" new_roles = regen_result[\\\"assignments\\\"]\\n\",\n \" new_role_dict = {r['role']: r for r in new_roles}\\n\",\n \" \\n\",\n \" # Build combined role set\\n\",\n \" combined_roles = []\\n\",\n \" selected_from_old = []\\n\",\n \" selected_from_new = []\\n\",\n \" \\n\",\n \" # Select from OLD\\n\",\n \" if old_keep == [\\\"*\\\"]:\\n\",\n \" combined_roles.extend(old_roles)\\n\",\n \" selected_from_old = [r['role'] for r in old_roles]\\n\",\n \" else:\\n\",\n \" for role_name in old_keep:\\n\",\n \" if role_name in old_role_dict:\\n\",\n \" combined_roles.append(old_role_dict[role_name])\\n\",\n \" selected_from_old.append(role_name)\\n\",\n \" else:\\n\",\n \" print(f\\\" [WARN] {db_name}: OLD role '{role_name}' not found\\\")\\n\",\n \" \\n\",\n \" # Select from NEW\\n\",\n \" if new_keep == [\\\"*\\\"]:\\n\",\n \" combined_roles.extend(new_roles)\\n\",\n \" selected_from_new = [r['role'] for r in new_roles]\\n\",\n \" else:\\n\",\n \" for role_name in new_keep:\\n\",\n \" if role_name in new_role_dict:\\n\",\n \" combined_roles.append(new_role_dict[role_name])\\n\",\n \" selected_from_new.append(role_name)\\n\",\n \" else:\\n\",\n \" print(f\\\" [WARN] {db_name}: NEW role '{role_name}' not found\\\")\\n\",\n \" \\n\",\n \" combined_results[db_name] = combined_roles\\n\",\n \" \\n\",\n \" # Display summary\\n\",\n \" print(f\\\"{'='*60}\\\")\\n\",\n \" print(f\\\"Database: {db_name}\\\")\\n\",\n \" print(f\\\" From OLD ({len(selected_from_old)}): {selected_from_old if selected_from_old else '(none)'}\\\")\\n\",\n \" print(f\\\" From NEW ({len(selected_from_new)}): {selected_from_new if selected_from_new else '(none)'}\\\")\\n\",\n \" print(f\\\" Combined: {len(combined_roles)} roles\\\")\\n\",\n \" \\n\",\n \" # Show combined roles table\\n\",\n \" target_schema = target_schemas.get(db_name)\\n\",\n \" combined_summary = []\\n\",\n \" for r in combined_roles:\\n\",\n \" policy = r.get('policy', {})\\n\",\n \" source = \\\"OLD\\\" if r['role'] in old_role_dict and r['role'] not in [nr['role'] for nr in new_roles] else \\\"NEW\\\"\\n\",\n \" if r['role'] in old_role_dict and r['role'] in [nr['role'] for nr in new_roles]:\\n\",\n \" source = \\\"NEW\\\" # Prefer NEW if same name exists in both\\n\",\n \" combined_summary.append({\\n\",\n \" \\\"Source\\\": source,\\n\",\n \" \\\"Role\\\": r['role'],\\n\",\n \" \\\"Description\\\": r.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Policy\\\": \\\"; \\\".join([f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" for t, c in policy.items()])\\n\",\n \" })\\n\",\n \" \\n\",\n \" display(pd.DataFrame(combined_summary))\\n\",\n \" print()\\n\",\n \" \\n\",\n \" print(\\\"=\\\"*60)\\n\",\n \" print(f\\\"[NEXT] Run Cell 6.5 to apply combined role sets\\\")\\n\",\n \" print(\\\"[TIP] Edit ROLE_SELECTION above to customize, then re-run this cell\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[WARN] No regenerated results. Run Cell 6.3 first.\\\")\\n\",\n \" print(\\\"\\\\n[HINT] Available roles to select from:\\\")\\n\",\n \" print(\\\" OLD: roles from current assignments\\\")\\n\",\n \" print(\\\" NEW: roles from regeneration\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 71,\n \"id\": \"6cb24c7d\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[MODE] Applying COMBINED role sets (from Cell 6.4.1 selection)\\n\",\n \"\\n\",\n \"=== Changes Applied ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseOld RolesNew RolesSource
0formula_154Combined (OLD+NEW)
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Old Roles New Roles Source\\n\",\n \"0 formula_1 5 4 Combined (OLD+NEW)\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"Saved to: bird_column_level_rbac_assignments_v2_20251230.json\\n\",\n \"\\n\",\n \"[OK] State cleared. Select new database(s) to continue.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.5 Apply Changes (Save Combined Role Sets)\\n\",\n \"# Uses combined_results from Cell 6.4.1 (selected from OLD + NEW)\\n\",\n \"from datetime import datetime\\n\",\n \"\\n\",\n \"APPLY_CHANGES = True # Set to True to confirm\\n\",\n \"\\n\",\n \"if APPLY_CHANGES:\\n\",\n \" # Prefer combined_results (from selection), fallback to regenerated_results\\n\",\n \" use_combined = 'combined_results' in dir() and combined_results\\n\",\n \" use_regenerated = 'regenerated_results' in dir() and regenerated_results\\n\",\n \" \\n\",\n \" if use_combined:\\n\",\n \" print(\\\"[MODE] Applying COMBINED role sets (from Cell 6.4.1 selection)\\\\n\\\")\\n\",\n \" applied = []\\n\",\n \" \\n\",\n \" for db_name, combined_roles in combined_results.items():\\n\",\n \" if not combined_roles:\\n\",\n \" continue\\n\",\n \" \\n\",\n \" old_count = len(all_assignments.get('assignments', {}).get(db_name, []))\\n\",\n \" all_assignments['assignments'][db_name] = combined_roles\\n\",\n \" applied.append({\\n\",\n \" \\\"Database\\\": db_name,\\n\",\n \" \\\"Old Roles\\\": old_count,\\n\",\n \" \\\"New Roles\\\": len(combined_roles),\\n\",\n \" \\\"Source\\\": \\\"Combined (OLD+NEW)\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" if applied:\\n\",\n \" OUTPUT_DIR = project_root / 'outputs'\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = OUTPUT_DIR / f'bird_column_level_rbac_assignments_v2_{today}.json'\\n\",\n \" with open(output_path, 'w') as f:\\n\",\n \" json.dump(all_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \" \\n\",\n \" print(\\\"=== Changes Applied ===\\\")\\n\",\n \" display(pd.DataFrame(applied))\\n\",\n \" print(f\\\"\\\\nSaved to: {output_path.name}\\\")\\n\",\n \" \\n\",\n \" # Clear state\\n\",\n \" combined_results = {}\\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"\\\\n[OK] State cleared. Select new database(s) to continue.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No combined role sets to apply. Run Cell 6.4.1 first.\\\")\\n\",\n \" \\n\",\n \" elif use_regenerated:\\n\",\n \" print(\\\"[MODE] Applying ALL NEW roles (no selection made)\\\\n\\\")\\n\",\n \" applied = []\\n\",\n \" \\n\",\n \" for db_name, regen_result in regenerated_results.items():\\n\",\n \" if regen_result[\\\"status\\\"] != \\\"success\\\":\\n\",\n \" continue\\n\",\n \" \\n\",\n \" old_count = len(all_assignments.get('assignments', {}).get(db_name, []))\\n\",\n \" all_assignments['assignments'][db_name] = regen_result[\\\"assignments\\\"]\\n\",\n \" applied.append({\\n\",\n \" \\\"Database\\\": db_name,\\n\",\n \" \\\"Old Roles\\\": old_count,\\n\",\n \" \\\"New Roles\\\": len(regen_result[\\\"assignments\\\"]),\\n\",\n \" \\\"Source\\\": \\\"All NEW\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" if applied:\\n\",\n \" OUTPUT_DIR = project_root / 'outputs'\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = OUTPUT_DIR / f'bird_column_level_rbac_assignments_v2_{today}.json'\\n\",\n \" with open(output_path, 'w') as f:\\n\",\n \" json.dump(all_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \" \\n\",\n \" print(\\\"=== Changes Applied ===\\\")\\n\",\n \" display(pd.DataFrame(applied))\\n\",\n \" print(f\\\"\\\\nSaved to: {output_path.name}\\\")\\n\",\n \" \\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"\\\\n[OK] State cleared. Select new database(s) to continue.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No successful regenerations to apply.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No results to apply. Run Cell 6.3 and optionally Cell 6.4.1 first.\\\")\\n\",\n \"else:\\n\",\n \" has_combined = 'combined_results' in dir() and combined_results\\n\",\n \" has_regenerated = 'regenerated_results' in dir() and regenerated_results\\n\",\n \" \\n\",\n \" if has_combined:\\n\",\n \" print(f\\\"[INFO] {len(combined_results)} database(s) with COMBINED role sets ready\\\")\\n\",\n \" print(\\\"[TIP] These are your custom selections from OLD + NEW\\\")\\n\",\n \" elif has_regenerated:\\n\",\n \" success_count = sum(1 for r in regenerated_results.values() if r[\\\"status\\\"] == \\\"success\\\")\\n\",\n \" print(f\\\"[INFO] {success_count} database(s) with ALL NEW roles ready\\\")\\n\",\n \" print(\\\"[TIP] Run Cell 6.4.1 to select specific roles from OLD/NEW\\\")\\n\",\n \" \\n\",\n \" print(\\\"\\\\n[INFO] APPLY_CHANGES is False. Set to True and re-run to apply.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"f1bd0bc2\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 6.6 Regenerate RBAC Dataset with Updated Role Assignments\\n\",\n \"# Run this after Cell 6.5 to create the final dataset\\n\",\n \"\\n\",\n \"from datetime import datetime\\n\",\n \"import importlib\\n\",\n \"\\n\",\n \"# IMPORTANT: Reload ALL dependent modules to pick up CTE parsing fix\\n\",\n \"import src.processors.column_extractor\\n\",\n \"import src.processors.column_permission_checker\\n\",\n \"import src.processors.column_level_rbac_generator\\n\",\n \"\\n\",\n \"importlib.reload(src.processors.column_extractor)\\n\",\n \"importlib.reload(src.processors.column_permission_checker)\\n\",\n \"importlib.reload(src.processors.column_level_rbac_generator)\\n\",\n \"\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator\\n\",\n \"\\n\",\n \"# Find the updated role assignments file (v2 if exists, otherwise latest)\\n\",\n \"v2_files = sorted(glob.glob(str(project_root / 'outputs' / 'bird_column_level_rbac_assignments_v2_*.json')))\\n\",\n \"if v2_files:\\n\",\n \" UPDATED_ROLE_PATH = v2_files[-1]\\n\",\n \"else:\\n\",\n \" role_files = sorted(glob.glob(str(project_root / 'outputs' / 'column_level_role_assignments_bird_*.json')))\\n\",\n \" UPDATED_ROLE_PATH = role_files[-1] if role_files else None\\n\",\n \"\\n\",\n \"if UPDATED_ROLE_PATH:\\n\",\n \" print(f\\\"=== Regenerating RBAC Dataset ===\\\")\\n\",\n \" print(f\\\"Role assignments: {Path(UPDATED_ROLE_PATH).name}\\\")\\n\",\n \" print(f\\\"BIRD data: {BIRD_DATA_PATH}\\\")\\n\",\n \" \\n\",\n \" # Initialize generator with updated roles\\n\",\n \" generator = ColumnLevelRBACGenerator(\\n\",\n \" role_assignments_path=UPDATED_ROLE_PATH,\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH),\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" project_root=str(project_root),\\n\",\n \" seed=42\\n\",\n \" )\\n\",\n \" \\n\",\n \" # Generate dataset\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = project_root / 'outputs' / f'column_level_rbac_dataset_bird_{today}.json'\\n\",\n \" \\n\",\n \" full_stats = generator.generate_and_save(\\n\",\n \" output_path=str(output_path),\\n\",\n \" roles_per_db=None,\\n\",\n \" queries_per_role=None\\n\",\n \" )\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n✓ Dataset saved to: {output_path.name}\\\")\\n\",\n \" print(f\\\"\\\\n=== Dataset Statistics ===\\\")\\n\",\n \" for k, v in full_stats.items():\\n\",\n \" if k == 'by_database':\\n\",\n \" print(f\\\"\\\\nPer-database distribution:\\\")\\n\",\n \" for db_id, counts in sorted(v.items()):\\n\",\n \" print(f\\\" {db_id}: allowed={counts['allowed']}, denied={counts['denied']}\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[ERROR] No role assignments file found. Run Cell 6.5 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"a9345c97\",\n \"metadata\": {},\n \"source\": [\n \"## 7. Summary\\n\",\n \"\\n\",\n \"### Generated Files\\n\",\n \"- `outputs/column_level_role_assignments_bird_YYYYMMDD.json` - Role assignments with column-level policies\\n\",\n \"- `outputs/bird_column_level_rbac_assignments_v2_YYYYMMDD.json` - Updated role assignments after regeneration\\n\",\n \"- `outputs/column_level_rbac_dataset_bird_YYYYMMDD.json` - Column-Level RBAC dataset\\n\",\n \"\\n\",\n \"### Workflow\\n\",\n \"\\n\",\n \"| Section | Description |\\n\",\n \"|---------|-------------|\\n\",\n \"| **3** | Batch process all BIRD databases to generate initial roles |\\n\",\n \"| **4** | Generate RBAC dataset from role assignments |\\n\",\n \"| **5** | Quality assessment with configurable thresholds |\\n\",\n \"| **6.1** | Select problematic database(s) and view current state |\\n\",\n \"| **6.2** | Write regeneration hints with problem description |\\n\",\n \"| **6.3** | Execute LLM regeneration with hints |\\n\",\n \"| **6.4** | Preview OLD vs NEW roles with quality comparison |\\n\",\n \"| **6.4.1** | Select & combine best roles from OLD and NEW |\\n\",\n \"| **6.5** | Apply changes (save updated role assignments) |\\n\",\n \"| **6.6** | Regenerate RBAC dataset with updated roles |\\n\",\n \"\\n\",\n \"### Quality Assessment Module (Section 5)\\n\",\n \"\\n\",\n \"```python\\n\",\n \"from src.role_evaluator import RoleQualityEvaluator, RoleQualityVisualizer\\n\",\n \"\\n\",\n \"evaluator = RoleQualityEvaluator(\\n\",\n \" role_assignments_path=\\\"outputs/column_level_role_assignments_bird.json\\\",\\n\",\n \" dataset_path=\\\"outputs/column_level_rbac_dataset_bird.json\\\",\\n\",\n \" schema_dir=\\\"data/Bird/dev_20251106/dev_databases\\\",\\n\",\n \" embed_model=\\\"BAAI/bge-small-en-v1.5\\\" # or \\\"text-embedding-3-small\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"report = evaluator.evaluate_all()\\n\",\n \"visualizer = RoleQualityVisualizer(evaluator=evaluator, report=report)\\n\",\n \"visualizer.plot_quality_dashboard()\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Quality Thresholds (Configurable)\\n\",\n \"\\n\",\n \"| Metric | Default | Description |\\n\",\n \"|--------|---------|-------------|\\n\",\n \"| `deny_rate_min` | 5% | Warn if deny rate below (roles too permissive) |\\n\",\n \"| `coverage_max` | 90% | Warn if avg coverage above (roles too broad) |\\n\",\n \"| `coverage_std_min` | 0.08 | Warn if coverage std below (low diversity) |\\n\",\n \"| `max_overlap` | 80% | Warn if max overlap above (redundant roles) |\\n\",\n \"\\n\",\n \"### External Modules\\n\",\n \"\\n\",\n \"1. **`src/role_evaluator/quality_metrics.py`** - Quality metrics computation\\n\",\n \" - `RoleQualityEvaluator`: Comprehensive evaluator\\n\",\n \" - `DenyRateMetrics`, `SemanticMetrics`, `OverlapMetrics`: Data classes\\n\",\n \" - `print_quality_report()`: Formatted report output\\n\",\n \"\\n\",\n \"2. **`src/role_evaluator/quality_visualizer.py`** - Visualization suite\\n\",\n \" - `plot_deny_rate_distribution()`: Permission distribution chart\\n\",\n \" - `plot_semantic_alignment()`: Semantic alignment scatter plot\\n\",\n \" - `plot_policy_overlap_bars()`: Policy overlap bar chart\\n\",\n \" - `plot_quality_dashboard()`: Comprehensive dashboard\\n\",\n \"\\n\",\n \"3. **`src/processors/column_level_rbac_generator.py`** - Dataset generation\\n\",\n \" - `ColumnLevelRBACGenerator`: Generate RBAC dataset from role assignments\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \"llm4db\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.10.18\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"}, "5cc57acf0416355bbf429707237d4389c7ecaebe": {"t": 1785753616.5686216, "n": 162988, "h": "a254ef89eada166d", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"id\": \"c4bddd25\",\n \"metadata\": {},\n \"source\": [\n \"## 0. Import and Setup\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"93292a4c\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Setup and imports\\n\",\n \"import sys\\n\",\n \"import json\\n\",\n \"import sqlite3\\n\",\n \"from pathlib import Path\\n\",\n \"from pprint import pprint\\n\",\n \"\\n\",\n \"# Add project root to path\\n\",\n \"project_root = Path.cwd().parent\\n\",\n \"sys.path.insert(0, str(project_root))\\n\",\n \"\\n\",\n \"print(f\\\"Project root: {project_root}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 2,\n \"id\": \"bce399e4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Available API keys:\\n\",\n \" OPENAI_API_KEY: ✓\\n\",\n \" DEEPSEEK_API_KEY: ✓\\n\",\n \" DEEPINFRA_API_KEY: ✓\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Load environment and initialize Oracle\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"import os\\n\",\n \"\\n\",\n \"load_dotenv(project_root / '.env')\\n\",\n \"\\n\",\n \"# Check available API keys\\n\",\n \"api_keys = {\\n\",\n \" 'OPENAI_API_KEY': bool(os.getenv('OPENAI_API_KEY')),\\n\",\n \" 'DEEPSEEK_API_KEY': bool(os.getenv('DEEPSEEK_API_KEY')),\\n\",\n \" 'DEEPINFRA_API_KEY': bool(os.getenv('DEEPINFRA_API_KEY')),\\n\",\n \"}\\n\",\n \"print(\\\"Available API keys:\\\")\\n\",\n \"for k, v in api_keys.items():\\n\",\n \" print(f\\\" {k}: {'✓' if v else '✗'}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"a4d69b7c\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Initialize LLM Oracle\\n\",\n \"from src.llm_oracle import Oracle\\n\",\n \"\\n\",\n \"# Choose model based on available keys (prefer DeepSeek for cost efficiency)\\n\",\n \"if os.getenv('DEEPSEEK_API_KEY'):\\n\",\n \" MODEL = \\\"deepseek-chat\\\"\\n\",\n \" API_KEY = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"elif os.getenv('OPENAI_API_KEY'):\\n\",\n \" MODEL = \\\"gpt-4o-mini\\\"\\n\",\n \" API_KEY = os.getenv('OPENAI_API_KEY')\\n\",\n \"else:\\n\",\n \" raise ValueError(\\\"No API key available!\\\")\\n\",\n \"\\n\",\n \"oracle = Oracle(model=MODEL, apikey=API_KEY)\\n\",\n \"print(f\\\"Using model: {MODEL}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8809cf55\",\n \"metadata\": {},\n \"source\": [\n \"## 1. Load Sample Database Schema\\n\",\n \"\\n\",\n \"We'll use a BIRD database with interesting column structure for testing.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 4,\n \"id\": \"e9dcc61c\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Import shared policy utility functions\\n\",\n \"from src.role_evaluator.quality_metrics import RoleQualityEvaluator\\n\",\n \"\\n\",\n \"# Convenience aliases for the static methods\\n\",\n \"count_policy_columns = RoleQualityEvaluator.count_policy_columns\\n\",\n \"has_wildcard_policy = RoleQualityEvaluator.has_wildcard_policy\\n\",\n \"\\n\",\n \"def get_schema_from_sqlite(db_path: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Extract detailed schema from SQLite database.\\\"\\\"\\\"\\n\",\n \" conn = sqlite3.connect(db_path)\\n\",\n \" cursor = conn.cursor()\\n\",\n \" \\n\",\n \" # Get all tables\\n\",\n \" cursor.execute(\\\"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'\\\")\\n\",\n \" tables = [row[0] for row in cursor.fetchall()]\\n\",\n \" \\n\",\n \" schema = {}\\n\",\n \" for table in tables:\\n\",\n \" cursor.execute(f\\\"PRAGMA table_info(`{table}`)\\\")\\n\",\n \" columns = cursor.fetchall()\\n\",\n \" \\n\",\n \" cursor.execute(f\\\"PRAGMA foreign_key_list(`{table}`)\\\")\\n\",\n \" fks = {row[3]: f\\\"{row[2]}.{row[4]}\\\" for row in cursor.fetchall()}\\n\",\n \" \\n\",\n \" schema[table] = {\\n\",\n \" 'columns': [\\n\",\n \" {\\n\",\n \" 'name': col[1],\\n\",\n \" 'type': col[2] or 'TEXT',\\n\",\n \" 'pk': col[5] == 1,\\n\",\n \" 'not_null': col[3] == 1,\\n\",\n \" 'fk': fks.get(col[1])\\n\",\n \" }\\n\",\n \" for col in columns\\n\",\n \" ]\\n\",\n \" }\\n\",\n \" \\n\",\n \" conn.close()\\n\",\n \" return schema\\n\",\n \"\\n\",\n \"def format_schema_for_prompt(schema: dict, db_name: str) -> str:\\n\",\n \" \\\"\\\"\\\"Format schema as text for LLM prompt.\\\"\\\"\\\"\\n\",\n \" lines = [f\\\"Database: {db_name}\\\\n\\\"]\\n\",\n \" \\n\",\n \" for table, info in schema.items():\\n\",\n \" lines.append(f\\\"Table: {table}\\\")\\n\",\n \" lines.append(\\\"Columns:\\\")\\n\",\n \" for col in info['columns']:\\n\",\n \" constraints = []\\n\",\n \" if col['pk']:\\n\",\n \" constraints.append(\\\"PRIMARY KEY\\\")\\n\",\n \" if col['not_null'] and not col['pk']:\\n\",\n \" constraints.append(\\\"NOT NULL\\\")\\n\",\n \" if col['fk']:\\n\",\n \" constraints.append(f\\\"FK -> {col['fk']}\\\")\\n\",\n \" \\n\",\n \" constraint_str = f\\\" [{', '.join(constraints)}]\\\" if constraints else \\\"\\\"\\n\",\n \" lines.append(f\\\" - {col['name']} ({col['type']}){constraint_str}\\\")\\n\",\n \" lines.append(\\\"\\\")\\n\",\n \" \\n\",\n \" return \\\"\\\\n\\\".join(lines)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 5,\n \"id\": \"705d64b1\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Available BIRD databases (11):\\n\",\n \" - california_schools\\n\",\n \" - card_games\\n\",\n \" - codebase_community\\n\",\n \" - debit_card_specializing\\n\",\n \" - european_football_2\\n\",\n \" - financial\\n\",\n \" - formula_1\\n\",\n \" - student_club\\n\",\n \" - superhero\\n\",\n \" - thrombosis_prediction\\n\",\n \" ...\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Load a sample BIRD database - use the latest 2025 version\\n\",\n \"bird_db_dir = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases'\\n\",\n \"\\n\",\n \"# List available databases\\n\",\n \"available_dbs = [d.name for d in bird_db_dir.iterdir() if d.is_dir()]\\n\",\n \"print(f\\\"Available BIRD databases ({len(available_dbs)}):\\\")\\n\",\n \"for db in sorted(available_dbs)[:10]:\\n\",\n \" print(f\\\" - {db}\\\")\\n\",\n \"print(\\\" ...\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"f9e1a86a\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Select a database with moderate complexity\\n\",\n \"# 'california_schools' has tables with sensitive-looking columns\\n\",\n \"TEST_DB = \\\"california_schools\\\"\\n\",\n \"db_path = bird_db_dir / TEST_DB / f\\\"{TEST_DB}.sqlite\\\"\\n\",\n \"\\n\",\n \"print(f\\\"Loading schema from: {db_path}\\\")\\n\",\n \"schema = get_schema_from_sqlite(str(db_path))\\n\",\n \"\\n\",\n \"print(f\\\"\\\\nTables: {list(schema.keys())}\\\")\\n\",\n \"for table, info in schema.items():\\n\",\n \" print(f\\\"\\\\n{table}: {len(info['columns'])} columns\\\")\\n\",\n \" for col in info['columns'][:5]:\\n\",\n \" print(f\\\" - {col['name']} ({col['type']})\\\")\\n\",\n \" if len(info['columns']) > 5:\\n\",\n \" print(f\\\" ... and {len(info['columns']) - 5} more\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 7,\n \"id\": \"e5fb0114\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Database: california_schools\\n\",\n \"\\n\",\n \"Table: frpm\\n\",\n \"Columns:\\n\",\n \" - CDSCode (TEXT) [PRIMARY KEY, FK -> schools.CDSCode]\\n\",\n \" - Academic Year (TEXT)\\n\",\n \" - County Code (TEXT)\\n\",\n \" - District Code (INTEGER)\\n\",\n \" - School Code (TEXT)\\n\",\n \" - County Name (TEXT)\\n\",\n \" - District Name (TEXT)\\n\",\n \" - School Name (TEXT)\\n\",\n \" - District Type (TEXT)\\n\",\n \" - School Type (TEXT)\\n\",\n \" - Educational Option Type (TEXT)\\n\",\n \" - NSLP Provision Status (TEXT)\\n\",\n \" - Charter School (Y/N) (INTEGER)\\n\",\n \" - Charter School Number (TEXT)\\n\",\n \" - Charter Funding Type (TEXT)\\n\",\n \" - IRC (INTEGER)\\n\",\n \" - Low Grade (TEXT)\\n\",\n \" - High Grade (TEXT)\\n\",\n \" - Enrollment (K-12) (REAL)\\n\",\n \" - Free Meal Count (K-12) (REAL)\\n\",\n \" - Percent (%) Eligible Free (K-12) (REAL)\\n\",\n \" - FRPM Count (K-12) (REAL)\\n\",\n \" - Percent (%) Eligible FRPM (K-12) (REAL)\\n\",\n \" - Enrollment (Ages 5-17) (REAL)\\n\",\n \" - Free Meal Count (Ages 5-17) (REAL)\\n\",\n \" - Percent (%) Eligible Free (Ages 5-17) (REAL)\\n\",\n \" - FRPM Count (Ages 5-17) (REAL)\\n\",\n \" - Percent (%) Eligible FRPM (Ages 5-17) (REAL)\\n\",\n \" - 2013-14 CALPADS Fall 1 Certification Status (INTEGER)\\n\",\n \"\\n\",\n \"Table: satscores\\n\",\n \"Columns:\\n\",\n \" - cds (TEXT) [PRIMARY KEY, FK -> schools.CDSCode]\\n\",\n \" - rtype (TEXT) [NOT NULL]\\n\",\n \" - sname (TEXT)\\n\",\n \" - dname (TEXT)\\n\",\n \" - cname (TEXT)\\n\",\n \" - enroll12 (INTEGER) [NOT NULL]\\n\",\n \" - NumTstTakr (INTEGER) [NOT NULL]\\n\",\n \" - AvgScrRead (INTEGER)\\n\",\n \" - AvgScrMath (INTEGER)\\n\",\n \" - AvgScrWrite (INTEGER)\\n\",\n \" - NumGE1500 (INTEGER)\\n\",\n \"\\n\",\n \"Table: schools\\n\",\n \"Columns:\\n\",\n \" - CDSCode (TEXT) [PRIMARY KEY]\\n\",\n \" - NCESDist (TEXT)\\n\",\n \" - NCESSchool (TEXT)\\n\",\n \" - StatusType (TEXT) [NOT NULL]\\n\",\n \" - County (TEXT) [NOT NULL]\\n\",\n \" - District (TEXT) [NOT NULL]\\n\",\n \" - School (TEXT)\\n\",\n \" - Street (TEXT)\\n\",\n \" - StreetAbr (TEXT)\\n\",\n \" - City (TEXT)\\n\",\n \" - Zip (TEXT)\\n\",\n \" - State (TEXT)\\n\",\n \" - MailStreet (TEXT)\\n\",\n \" - MailStrAbr (TEXT)\\n\",\n \" - MailCity (TEXT)\\n\",\n \" - MailZip (TEXT)\\n\",\n \" - MailState (TEXT)\\n\",\n \" - Phone (TEXT)\\n\",\n \" - Ext (TEXT)\\n\",\n \" - Website (TEXT)\\n\",\n \" - OpenDate (DATE)\\n\",\n \" - ClosedDate (DATE)\\n\",\n \" - Charter (INTEGER)\\n\",\n \" - CharterNum (TEXT)\\n\",\n \" - FundingType (TEXT)\\n\",\n \" - DOC (TEXT) [NOT NULL]\\n\",\n \" - DOCType (TEXT) [NOT NULL]\\n\",\n \" - SOC (TEXT)\\n\",\n \" - SOCType (TEXT)\\n\",\n \" - EdOpsCode (TEXT)\\n\",\n \" \\n\",\n \"\\n\",\n \"... (total 2401 characters)\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Format schema for prompt\\n\",\n \"schema_text = format_schema_for_prompt(schema, TEST_DB)\\n\",\n \"print(schema_text[:2000])\\n\",\n \"print(f\\\"\\\\n... (total {len(schema_text)} characters)\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8e904509\",\n \"metadata\": {},\n \"source\": [\n \"## 2. Load Prompts from External Modules\\n\",\n \"\\n\",\n \"Prompts are now defined in `configs/column_level_prompts.py`.\\n\",\n \"- **JSON format** is used (more structured, requires max_tokens=4000)\\n\",\n \"- Parser auto-detects format and handles both JSON and Plain Text\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 8,\n \"id\": \"1a425645\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Loaded from external modules:\\n\",\n \" - COLUMN_LEVEL_SYSTEM_PROMPT (2734 chars)\\n\",\n \" - COLUMN_LEVEL_USER_PROMPT_TEMPLATE\\n\",\n \" - DEFAULT_MAX_TOKENS = 4000\\n\",\n \" - parse_column_level_roles (auto-detects JSON/Text)\\n\",\n \" - validate_roles_against_schema\\n\",\n \"\\n\",\n \"--- System Prompt Preview ---\\n\",\n \"You are a database security expert specializing in fine-grained Role-Based Access Control (RBAC).\\n\",\n \"Your job is to read a relational database schema and propose a COHERENT set of roles with COLUMN-LEVEL permissions.\\n\",\n \"\\n\",\n \"Key goals:\\n\",\n \"- Minimize role count while covering real-world workflows (decide number of roles according to real world scenario).\\n\",\n \"- Each role must be clearly related to others (same scenario, complementary duties).\\n\",\n \"- Enforce least-privilege at the COLUMN level (specify which columns eac\\n\",\n \"...\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Reload modules to get latest changes\\n\",\n \"import importlib\\n\",\n \"import configs.column_level_prompts\\n\",\n \"import src.role_parser.column_level_parser\\n\",\n \"importlib.reload(configs.column_level_prompts)\\n\",\n \"importlib.reload(src.role_parser.column_level_parser)\\n\",\n \"\\n\",\n \"# Import prompts and parser from external modules\\n\",\n \"from configs.column_level_prompts import (\\n\",\n \" COLUMN_LEVEL_SYSTEM_PROMPT, \\n\",\n \" COLUMN_LEVEL_USER_PROMPT_TEMPLATE,\\n\",\n \" DEFAULT_MAX_TOKENS\\n\",\n \")\\n\",\n \"from src.role_parser import parse_column_level_roles, validate_roles_against_schema\\n\",\n \"\\n\",\n \"print(\\\"✓ Loaded from external modules:\\\")\\n\",\n \"print(f\\\" - COLUMN_LEVEL_SYSTEM_PROMPT ({len(COLUMN_LEVEL_SYSTEM_PROMPT)} chars)\\\")\\n\",\n \"print(f\\\" - COLUMN_LEVEL_USER_PROMPT_TEMPLATE\\\")\\n\",\n \"print(f\\\" - DEFAULT_MAX_TOKENS = {DEFAULT_MAX_TOKENS}\\\")\\n\",\n \"print(f\\\" - parse_column_level_roles (auto-detects JSON/Text)\\\")\\n\",\n \"print(f\\\" - validate_roles_against_schema\\\")\\n\",\n \"\\n\",\n \"print(\\\"\\\\n--- System Prompt Preview ---\\\")\\n\",\n \"print(COLUMN_LEVEL_SYSTEM_PROMPT[:500])\\n\",\n \"print(\\\"...\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"0acacb6e\",\n \"metadata\": {},\n \"source\": [\n \"## [Archived] Single-Sample Experiments\\n\",\n \"\\n\",\n \"The following code block contains single sample test code for debugging prompt and parser.\\n\",\n \"**Commented out. For production, skip to Section 8 for batch processing.**\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 9,\n \"id\": \"e9700ae1\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"⏭️ This cell is commented out. Skip to Section 8 for batch processing.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# ============================================================\\n\",\n \"# [ARCHIVED] Single sample experiment code - commented out, skip this cell\\n\",\n \"# ============================================================\\n\",\n \"# The following code is for testing and debugging a single database\\n\",\n \"# For production, skip to Section 8 for batch processing\\n\",\n \"\\n\",\n \"'''\\n\",\n \"# --- 3. Generate Column-Level Roles (Single DB) ---\\n\",\n \"print(\\\"Generating column-level roles...\\\")\\n\",\n \"user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=schema_text)\\n\",\n \"response = oracle.query(\\n\",\n \" prompt_sys=COLUMN_LEVEL_SYSTEM_PROMPT,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3, top_p=0.9,\\n\",\n \" max_completion_tokens=DEFAULT_MAX_TOKENS\\n\",\n \")\\n\",\n \"llm_response = response['answer']\\n\",\n \"print(f\\\"Response length: {len(llm_response)} chars\\\")\\n\",\n \"\\n\",\n \"# --- 4. Parse and Validate ---\\n\",\n \"from src.role_parser.column_level_parser import parse_column_level_roles\\n\",\n \"parsed_roles = parse_column_level_roles(llm_response)\\n\",\n \"print(f\\\"Parsed {len(parsed_roles)} roles\\\")\\n\",\n \"\\n\",\n \"validation = validate_roles_against_schema(parsed_roles, str(db_path))\\n\",\n \"print(f\\\"Valid: {validation['valid_roles']}/{validation['total_roles']}\\\")\\n\",\n \"\\n\",\n \"# --- 5. Show Results ---\\n\",\n \"for role in parsed_roles:\\n\",\n \" print(f\\\" - {role['role']}: {len(role.get('columns', {}))} tables\\\")\\n\",\n \"\\n\",\n \"# --- 6. Compare with Table-Level ---\\n\",\n \"from configs.prompts import SYSTEM_PROMPT as TABLE_LEVEL_PROMPT, USER_PROMPT_TEMPLATE\\n\",\n \"table_level_response = oracle.query(\\n\",\n \" prompt_sys=TABLE_LEVEL_PROMPT,\\n\",\n \" prompt_user=USER_PROMPT_TEMPLATE.format(schema_content=schema_text),\\n\",\n \" temp=0.3, top_p=0.9\\n\",\n \")\\n\",\n \"print(\\\"Table-Level Response:\\\", table_level_response['answer'][:500])\\n\",\n \"\\n\",\n \"# --- 7. Save Single DB Result ---\\n\",\n \"def convert_to_assignment_format(parsed_roles, db_name):\\n\",\n \" return {\\\"assignments\\\": {db_name: [\\n\",\n \" {\\\"role\\\": r[\\\"role\\\"], \\\"description\\\": r.get(\\\"description\\\", \\\"\\\"), \\\"policy\\\": r.get(\\\"columns\\\", {})}\\n\",\n \" for r in parsed_roles\\n\",\n \" ]}}\\n\",\n \"\\n\",\n \"column_level_assignments = convert_to_assignment_format(parsed_roles, TEST_DB)\\n\",\n \"output_file = project_root / 'outputs' / 'column_level_role_assignments.json'\\n\",\n \"with open(output_file, 'w') as f:\\n\",\n \" json.dump(column_level_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \"print(f\\\"Saved to: {output_file}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ This cell is commented out. Skip to Section 8 for batch processing.\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8bc8cb95\",\n \"metadata\": {},\n \"source\": [\n \"## 3. Batch Process All BIRD Databases\\n\",\n \"\\n\",\n \"Generate column-level role assignments for all BIRD databases with parallel processing.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 10,\n \"id\": \"fe3f2e81\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Configuration:\\n\",\n \" Workers: 40\\n\",\n \" Databases: 11\\n\",\n \" Max tokens: 4000\\n\",\n \" Model: deepseek-chat\\n\",\n \"\\n\",\n \"Databases to process:\\n\",\n \" - superhero\\n\",\n \" - thrombosis_prediction\\n\",\n \" - student_club\\n\",\n \" - toxicology\\n\",\n \" - california_schools\\n\",\n \" - debit_card_specializing\\n\",\n \" - card_games\\n\",\n \" - codebase_community\\n\",\n \" - formula_1\\n\",\n \" - european_football_2\\n\",\n \" - financial\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Batch processing configuration\\n\",\n \"from concurrent.futures import ThreadPoolExecutor, as_completed\\n\",\n \"from tqdm.notebook import tqdm\\n\",\n \"\\n\",\n \"# Configuration\\n\",\n \"WORKERS = 40\\n\",\n \"SAMPLES = 100 # 0 for all databases\\n\",\n \"MAX_TOKENS = DEFAULT_MAX_TOKENS\\n\",\n \"\\n\",\n \"# Get all BIRD databases\\n\",\n \"all_dbs = [d.name for d in bird_db_dir.iterdir() if d.is_dir()]\\n\",\n \"if SAMPLES > 0:\\n\",\n \" all_dbs = all_dbs[:SAMPLES]\\n\",\n \"\\n\",\n \"print(f\\\"Configuration:\\\")\\n\",\n \"print(f\\\" Workers: {WORKERS}\\\")\\n\",\n \"print(f\\\" Databases: {len(all_dbs)}\\\")\\n\",\n \"print(f\\\" Max tokens: {MAX_TOKENS}\\\")\\n\",\n \"print(f\\\" Model: {MODEL}\\\")\\n\",\n \"print(f\\\"\\\\nDatabases to process:\\\")\\n\",\n \"for db in all_dbs:\\n\",\n \" print(f\\\" - {db}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 11,\n \"id\": \"7b5edd94\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Helper functions defined\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Helper functions for batch processing\\n\",\n \"\\n\",\n \"def process_single_database(db_name: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Process a single database and return role assignments.\\\"\\\"\\\"\\n\",\n \" db_path = bird_db_dir / db_name / f\\\"{db_name}.sqlite\\\"\\n\",\n \" \\n\",\n \" if not db_path.exists():\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": f\\\"Database not found\\\"}\\n\",\n \" \\n\",\n \" try:\\n\",\n \" # Extract schema\\n\",\n \" db_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" db_schema_text = format_schema_for_prompt(db_schema, db_name)\\n\",\n \" \\n\",\n \" # Generate roles via LLM\\n\",\n \" user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=db_schema_text)\\n\",\n \" \\n\",\n \" response = oracle.query(\\n\",\n \" prompt_sys=COLUMN_LEVEL_SYSTEM_PROMPT,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3,\\n\",\n \" top_p=0.9,\\n\",\n \" max_completion_tokens=MAX_TOKENS\\n\",\n \" )\\n\",\n \" \\n\",\n \" llm_response = response['answer']\\n\",\n \" usage = response.get('usage', {})\\n\",\n \" \\n\",\n \" # Parse response\\n\",\n \" roles = parse_column_level_roles(llm_response)\\n\",\n \" \\n\",\n \" if not roles:\\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"parse_error\\\",\\n\",\n \" \\\"error\\\": \\\"Failed to parse LLM response\\\",\\n\",\n \" \\\"raw_response\\\": llm_response[:300]\\n\",\n \" }\\n\",\n \" \\n\",\n \" # Validate against schema\\n\",\n \" validation = validate_roles_against_schema(roles, str(db_path))\\n\",\n \" \\n\",\n \" # Convert to target format\\n\",\n \" assignments = []\\n\",\n \" for role in roles:\\n\",\n \" assignments.append({\\n\",\n \" \\\"role\\\": role[\\\"role\\\"],\\n\",\n \" \\\"description\\\": role.get(\\\"description\\\", \\\"\\\"),\\n\",\n \" \\\"policy\\\": role.get(\\\"columns\\\", {})\\n\",\n \" })\\n\",\n \" \\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"success\\\",\\n\",\n \" \\\"roles_count\\\": len(assignments),\\n\",\n \" \\\"valid_roles\\\": validation['valid_roles'],\\n\",\n \" \\\"all_valid\\\": validation['all_valid'],\\n\",\n \" \\\"assignments\\\": assignments,\\n\",\n \" \\\"usage\\\": usage\\n\",\n \" }\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"error\\\",\\n\",\n \" \\\"error\\\": str(e)\\n\",\n \" }\\n\",\n \"\\n\",\n \"print(\\\"✓ Helper functions defined\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 12,\n \"id\": \"61e61795\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Starting batch processing with 40 workers...\\n\",\n \"============================================================\\n\",\n \"[1/11] ✓ toxicology: 4 roles (4 valid)\\n\",\n \"[2/11] ✓ debit_card_specializing: 4 roles (4 valid)\\n\",\n \"[3/11] ✓ thrombosis_prediction: 4 roles (4 valid)\\n\",\n \"[4/11] ✓ student_club: 5 roles (5 valid)\\n\",\n \"[5/11] ✓ superhero: 5 roles (5 valid)\\n\",\n \"[6/11] ✓ financial: 5 roles (5 valid)\\n\",\n \"[7/11] ✓ card_games: 5 roles (5 valid)\\n\",\n \"[8/11] ✓ codebase_community: 4 roles (4 valid)\\n\",\n \"[9/11] ✓ california_schools: 5 roles (5 valid)\\n\",\n \"[10/11] ✓ formula_1: 5 roles (5 valid)\\n\",\n \"[11/11] ✓ european_football_2: 5 roles (5 valid)\\n\",\n \"============================================================\\n\",\n \"Completed: 11/11 success, 0 errors\\n\",\n \"Total tokens: 25,679\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Execute batch processing with parallel workers\\n\",\n \"print(f\\\"Starting batch processing with {WORKERS} workers...\\\")\\n\",\n \"print(\\\"=\\\" * 60)\\n\",\n \"\\n\",\n \"results = {\\n\",\n \" \\\"metadata\\\": {\\n\",\n \" \\\"model\\\": MODEL,\\n\",\n \" \\\"max_tokens\\\": MAX_TOKENS,\\n\",\n \" \\\"total_databases\\\": len(all_dbs)\\n\",\n \" },\\n\",\n \" \\\"assignments\\\": {},\\n\",\n \" \\\"errors\\\": []\\n\",\n \"}\\n\",\n \"\\n\",\n \"success_count = 0\\n\",\n \"error_count = 0\\n\",\n \"total_tokens = {\\\"prompt\\\": 0, \\\"completion\\\": 0}\\n\",\n \"\\n\",\n \"with ThreadPoolExecutor(max_workers=WORKERS) as executor:\\n\",\n \" futures = {executor.submit(process_single_database, db): db for db in all_dbs}\\n\",\n \" \\n\",\n \" for i, future in enumerate(as_completed(futures), 1):\\n\",\n \" db_name = futures[future]\\n\",\n \" try:\\n\",\n \" result = future.result()\\n\",\n \" \\n\",\n \" if result[\\\"status\\\"] == \\\"success\\\":\\n\",\n \" results[\\\"assignments\\\"][result[\\\"database\\\"]] = result[\\\"assignments\\\"]\\n\",\n \" success_count += 1\\n\",\n \" \\n\",\n \" usage = result.get(\\\"usage\\\", {})\\n\",\n \" total_tokens[\\\"prompt\\\"] += usage.get(\\\"prompt_tokens\\\", 0)\\n\",\n \" total_tokens[\\\"completion\\\"] += usage.get(\\\"completion_tokens\\\", 0)\\n\",\n \" \\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✓ {db_name}: {result['roles_count']} roles ({result['valid_roles']} valid)\\\")\\n\",\n \" else:\\n\",\n \" results[\\\"errors\\\"].append(result)\\n\",\n \" error_count += 1\\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✗ {db_name}: {result.get('error', result['status'])}\\\")\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" error_count += 1\\n\",\n \" results[\\\"errors\\\"].append({\\\"database\\\": db_name, \\\"error\\\": str(e)})\\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✗ {db_name}: {e}\\\")\\n\",\n \"\\n\",\n \"results[\\\"metadata\\\"][\\\"success_count\\\"] = success_count\\n\",\n \"results[\\\"metadata\\\"][\\\"error_count\\\"] = error_count\\n\",\n \"results[\\\"metadata\\\"][\\\"total_tokens\\\"] = total_tokens\\n\",\n \"\\n\",\n \"print(\\\"=\\\" * 60)\\n\",\n \"print(f\\\"Completed: {success_count}/{len(all_dbs)} success, {error_count} errors\\\")\\n\",\n \"print(f\\\"Total tokens: {total_tokens['prompt'] + total_tokens['completion']:,}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"39d38aa3\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Save batch results to file\\n\",\n \"output_file = project_root / 'outputs' / 'column_level_role_assignments_bird.json'\\n\",\n \"\\n\",\n \"with open(output_file, 'w', encoding='utf-8') as f:\\n\",\n \" json.dump(results, f, indent=2, ensure_ascii=False)\\n\",\n \"\\n\",\n \"print(f\\\"✓ Results saved to: {output_file}\\\")\\n\",\n \"print(f\\\"\\\\nFile structure:\\\")\\n\",\n \"print(f\\\" - metadata: model, tokens, counts\\\")\\n\",\n \"print(f\\\" - assignments: {len(results['assignments'])} databases\\\")\\n\",\n \"print(f\\\" - errors: {len(results['errors'])} entries\\\")\\n\",\n \"\\n\",\n \"# Show sample\\n\",\n \"if results['assignments']:\\n\",\n \" sample_db = list(results['assignments'].keys())[0]\\n\",\n \" print(f\\\"\\\\nSample ({sample_db}):\\\")\\n\",\n \" print(json.dumps(results['assignments'][sample_db][:1], indent=2, ensure_ascii=False)[:500])\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"9595c46d\",\n \"metadata\": {},\n \"source\": [\n \"## 4. Generate Column-Level RBAC Dataset\\n\",\n \"\\n\",\n \"Based on the generated role policies, combined with BIRD dataset queries, generate the final RBAC training/evaluation dataset.\\n\",\n \"\\n\",\n \"Dataset format (consistent with table-level):\\n\",\n \"- `db_id`: Database name\\n\",\n \"- `instruction`: Full instruction with schema + evidence + role policy\\n\",\n \"- `role`: Role name\\n\",\n \"- `policy`: Column-level permission policy {table: [columns]}\\n\",\n \"- `input`: User question\\n\",\n \"- `output`: SQL or denial message\\n\",\n \"- `difficulty`: Query difficulty level\\n\",\n \"- `metadata`: Contains gold_sql, permission, query_columns, missing_columns, etc.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"405783fa\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 4.1 Import generator and test dependencies\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator, format_policy_text\\n\",\n \"from src.processors.column_extractor import extract_query_columns\\n\",\n \"from src.processors.column_permission_checker import check_column_permission\\n\",\n \"import glob\\n\",\n \"\\n\",\n \"# Configure paths - use 2025 version (dev_20251106) for latest BIRD data\\n\",\n \"ROLE_ASSIGNMENTS_PATH = project_root / 'outputs' / 'column_level_role_assignments_bird.json'\\n\",\n \"BIRD_DATA_PATH = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev.json'\\n\",\n \"BIRD_DB_ROOT = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases'\\n\",\n \"\\n\",\n \"print(\\\"=== Dataset Generation Config ===\\\")\\n\",\n \"print(f\\\"Role assignments: {ROLE_ASSIGNMENTS_PATH}\\\")\\n\",\n \"print(f\\\"BIRD data file: {BIRD_DATA_PATH}\\\")\\n\",\n \"print(f\\\"BIRD database dir: {BIRD_DB_ROOT}\\\")\\n\",\n \"\\n\",\n \"# Verify file existence\\n\",\n \"# assert ROLE_ASSIGNMENTS_PATH.exists(), f\\\"Role assignments file not found: {ROLE_ASSIGNMENTS_PATH}\\\"\\n\",\n \"assert BIRD_DATA_PATH.exists(), f\\\"BIRD data file not found: {BIRD_DATA_PATH}\\\"\\n\",\n \"assert BIRD_DB_ROOT.exists(), f\\\"BIRD database dir not found: {BIRD_DB_ROOT}\\\"\\n\",\n \"print(\\\"\\\\n✓ All file paths are valid\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4b80dc65\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== SQL Column Extraction Test ===\\n\",\n \"Tables: {'song', 'singer'}\\n\",\n \"Columns: {'song': {'singer_id', 'title'}, 'singer': {'id', 'name', 'country', 'age'}}\\n\",\n \"Has *: False\\n\",\n \"\\n\",\n \"=== Permission Check Test (Allow) ===\\n\",\n \"Allowed: True\\n\",\n \"Reason: All required columns are permitted\\n\",\n \"\\n\",\n \"=== Permission Check Test (Deny) ===\\n\",\n \"Allowed: False\\n\",\n \"Reason: Missing column permissions: song: singer_id; singer: age, country, id\\n\",\n \"Missing: {'song': {'singer_id'}, 'singer': {'id', 'country', 'age'}}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.2 Test SQL column extraction and permission checking\\n\",\n \"# Verified working, archived to simplify notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"test_sql = \\\"\\\"\\\"\\n\",\n \"SELECT singer.name, singer.age, song.title\\n\",\n \"FROM singer\\n\",\n \"JOIN song ON singer.id = song.singer_id\\n\",\n \"WHERE singer.country = 'USA'\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"print(\\\"=== SQL Column Extraction Test ===\\\")\\n\",\n \"info = extract_query_columns(test_sql)\\n\",\n \"print(f\\\"Tables: {info.tables}\\\")\\n\",\n \"print(f\\\"Columns: {info.columns}\\\")\\n\",\n \"print(f\\\"Has *: {info.has_star}\\\")\\n\",\n \"\\n\",\n \"# Test permission checking\\n\",\n \"policy_allow = {\\n\",\n \" 'singer': ['name', 'age', 'country', 'id'],\\n\",\n \" 'song': ['title', 'singer_id']\\n\",\n \"}\\n\",\n \"policy_deny = {\\n\",\n \" 'singer': ['name'], # Missing 'age', 'country', 'id'\\n\",\n \" 'song': ['title'] # Missing 'singer_id'\\n\",\n \"}\\n\",\n \"\\n\",\n \"print(\\\"\\\\n=== Permission Check Test (Allow) ===\\\")\\n\",\n \"result1 = check_column_permission(test_sql, policy_allow)\\n\",\n \"print(f\\\"Allowed: {result1.allowed}\\\")\\n\",\n \"print(f\\\"Reason: {result1.reason}\\\")\\n\",\n \"\\n\",\n \"print(\\\"\\\\n=== Permission Check Test (Deny) ===\\\")\\n\",\n \"result2 = check_column_permission(test_sql, policy_deny)\\n\",\n \"print(f\\\"Allowed: {result2.allowed}\\\")\\n\",\n \"print(f\\\"Reason: {result2.reason}\\\")\\n\",\n \"print(f\\\"Missing: {result2.missing_columns}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Column extraction/permission tests - verified\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 16,\n \"id\": \"0a018208\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Generator Initialized ===\\n\",\n \"Total BIRD queries: 1534\\n\",\n \"Databases with role assignments: 11\\n\",\n \"Databases with queries: 11\\n\",\n \"\\n\",\n \"Queries per database:\\n\",\n \" california_schools: 89\\n\",\n \" card_games: 191\\n\",\n \" codebase_community: 186\\n\",\n \" debit_card_specializing: 64\\n\",\n \" european_football_2: 129\\n\",\n \" financial: 106\\n\",\n \" formula_1: 174\\n\",\n \" student_club: 158\\n\",\n \" superhero: 129\\n\",\n \" thrombosis_prediction: 163\\n\",\n \" toxicology: 145\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 4.3 Initialize generator\\n\",\n \"generator = ColumnLevelRBACGenerator(\\n\",\n \" role_assignments_path=str(ROLE_ASSIGNMENTS_PATH),\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH),\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" project_root=str(project_root),\\n\",\n \" seed=42\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"=== Generator Initialized ===\\\")\\n\",\n \"print(f\\\"Total BIRD queries: {len(generator.bird_data)}\\\")\\n\",\n \"print(f\\\"Databases with role assignments: {len(generator.role_assignments.get('assignments', {}))}\\\")\\n\",\n \"print(f\\\"Databases with queries: {len(generator.queries_by_db)}\\\")\\n\",\n \"\\n\",\n \"# Show query counts per database\\n\",\n \"print(\\\"\\\\nQueries per database:\\\")\\n\",\n \"for db_id, queries in sorted(generator.queries_by_db.items()):\\n\",\n \" print(f\\\" {db_id}: {len(queries)}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"2a267246\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# [ARCHIVED] 4.4 Generate sample dataset (for format validation)\\n\",\n \"# Sample dataset used for debugging, production uses 4.5\\n\",\n \"\\n\",\n \"'''\\n\",\n \"print(\\\"=== Generating Sample Dataset ===\\\")\\n\",\n \"sample_stats = generator.generate_and_save(\\n\",\n \" output_path=str(project_root / 'outputs' / 'column_level_rbac_dataset_bird_sample.json'),\\n\",\n \" roles_per_db=1, # Use only 1 role per database\\n\",\n \" queries_per_role=3 # Use only 3 queries per role\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"\\\\\\\\nStatistics:\\\")\\n\",\n \"for k, v in sample_stats.items():\\n\",\n \" if k != 'by_database':\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Sample dataset generation - production uses 4.5\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4851fde0\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Data Format Validation ===\\n\",\n \"Total entries: 33\\n\",\n \"\\n\",\n \"--- Allowed Entry Example ---\\n\",\n \"db_id: toxicology\\n\",\n \"role: MolecularResearcher\\n\",\n \"policy: {\\\"molecule\\\": [\\\"molecule_id\\\", \\\"label\\\"], \\\"atom\\\": [\\\"atom_id\\\", \\\"molecule_id\\\", \\\"element\\\"], \\\"bond\\\": [\\\"bond...\\n\",\n \"input: What are the atom IDs of the bond TR000_2_5?...\\n\",\n \"output: SELECT T.atom_id FROM connected AS T WHERE T.bond_id = 'TR000_2_5'...\\n\",\n \"difficulty: simple\\n\",\n \"instruction length: 1887 chars\\n\",\n \"\\n\",\n \"--- Denied Entry Example ---\\n\",\n \"db_id: thrombosis_prediction\\n\",\n \"role: ClinicalResearcher\\n\",\n \"input: How old was the patient who had the highest hemoglobin count on the date of labo...\\n\",\n \"output: Sorry, I cannot answer.\\n\",\n \"missing_columns: {'patient': ['Diagnosis']}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.5-4.6 Validate generated data format & Show instruction example\\n\",\n \"# Data format verified, archived to simplify notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"sample_file = project_root / 'outputs' / 'column_level_rbac_dataset_bird_sample.json'\\n\",\n \"with open(sample_file, 'r') as f:\\n\",\n \" sample_data = json.load(f)\\n\",\n \"\\n\",\n \"print(\\\"=== Data Format Validation ===\\\")\\n\",\n \"print(f\\\"Total entries: {len(sample_data)}\\\")\\n\",\n \"\\n\",\n \"allowed_entry = next((e for e in sample_data if e['metadata']['permission'] == 'allowed'), None)\\n\",\n \"denied_entry = next((e for e in sample_data if e['metadata']['permission'] == 'denied'), None)\\n\",\n \"\\n\",\n \"if allowed_entry:\\n\",\n \" print(\\\"\\\\\\\\n--- Allowed Entry Example ---\\\")\\n\",\n \" print(f\\\"db_id: {allowed_entry['db_id']}\\\")\\n\",\n \" print(f\\\"role: {allowed_entry['role']}\\\")\\n\",\n \" print(f\\\"policy: {json.dumps(allowed_entry['policy'])[:100]}...\\\")\\n\",\n \" print(f\\\"input: {allowed_entry['input'][:80]}...\\\")\\n\",\n \" print(f\\\"output: {allowed_entry['output'][:80]}...\\\")\\n\",\n \"\\n\",\n \"if denied_entry:\\n\",\n \" print(\\\"\\\\\\\\n--- Denied Entry Example ---\\\")\\n\",\n \" print(f\\\"db_id: {denied_entry['db_id']}\\\")\\n\",\n \" print(f\\\"role: {denied_entry['role']}\\\")\\n\",\n \" print(f\\\"output: {denied_entry['output']}\\\")\\n\",\n \" print(f\\\"missing_columns: {denied_entry['metadata']['missing_columns']}\\\")\\n\",\n \"\\n\",\n \"# Show full instruction\\n\",\n \"print(\\\"\\\\\\\\n=== Full Instruction Example ===\\\")\\n\",\n \"if allowed_entry:\\n\",\n \" print(allowed_entry['instruction'][:2500])\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Data format validation - verified\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"c05e8787\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 4.5 Generate Full Column-Level RBAC Dataset\\n\",\n \"from datetime import datetime\\n\",\n \"\\n\",\n \"# Reload the modules to ensure we use the latest CTE fix\\n\",\n \"import importlib\\n\",\n \"import src.processors.column_extractor\\n\",\n \"import src.processors.column_permission_checker\\n\",\n \"import src.processors.column_level_rbac_generator\\n\",\n \"\\n\",\n \"importlib.reload(src.processors.column_extractor)\\n\",\n \"importlib.reload(src.processors.column_permission_checker)\\n\",\n \"importlib.reload(src.processors.column_level_rbac_generator)\\n\",\n \"\\n\",\n \"# Re-import with fresh code\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator\\n\",\n \"\\n\",\n \"# Re-create generator with fresh modules\\n\",\n \"generator = ColumnLevelRBACGenerator(\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" role_assignments_path=str(ROLE_ASSIGNMENTS_PATH),\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH)\\n\",\n \")\\n\",\n \"\\n\",\n \"# Output with date suffix\\n\",\n \"today = datetime.now().strftime('%Y%m%d')\\n\",\n \"output_path = project_root / 'outputs' / f'column_level_rbac_dataset_bird_{today}.json'\\n\",\n \"\\n\",\n \"print(\\\"=== Generating Full Column-Level RBAC Dataset ===\\\")\\n\",\n \"print(f\\\"Output: {output_path}\\\")\\n\",\n \"\\n\",\n \"full_stats = generator.generate_and_save(\\n\",\n \" output_path=str(output_path),\\n\",\n \" roles_per_db=None, # Use all roles (number varies per db based on LLM generation)\\n\",\n \" queries_per_role=None # Use all queries\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"\\\\nFull dataset statistics:\\\")\\n\",\n \"for k, v in full_stats.items():\\n\",\n \" if k == 'by_database':\\n\",\n \" print(f\\\"\\\\nPer-database distribution:\\\")\\n\",\n \" for db_id, counts in v.items():\\n\",\n \" print(f\\\" {db_id}: allowed={counts['allowed']}, denied={counts['denied']}\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" {k}: {v}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"2142ac6e\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Comparison with Table-Level Data Format ===\\n\",\n \"\\n\",\n \"--- Table-Level Entry Fields ---\\n\",\n \"['db_id', 'difficulty', 'input', 'instruction', 'metadata', 'output', 'role', 'tables']\\n\",\n \"\\n\",\n \"--- Column-Level Entry Fields ---\\n\",\n \"['db_id', 'difficulty', 'input', 'instruction', 'metadata', 'output', 'policy', 'role']\\n\",\n \"\\n\",\n \"Common fields: {'output', 'role', 'metadata', 'difficulty', 'db_id', 'input', 'instruction'}\\n\",\n \"Table-Level only: {'tables'}\\n\",\n \"Column-Level only: {'policy'}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.6 Compare with Table-Level format\\n\",\n \"# Format comparison completed, archived to simplify notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"print(\\\"=== Comparison with Table-Level Data Format ===\\\")\\n\",\n \"\\n\",\n \"table_level_file = project_root / 'data' / 'selected' / 'bird' / 'bird_dev_with_role_rbac.json'\\n\",\n \"if table_level_file.exists():\\n\",\n \" with open(table_level_file, 'r') as f:\\n\",\n \" table_level_data = json.load(f)\\n\",\n \" \\n\",\n \" print(\\\"\\\\\\\\n--- Table-Level Entry Fields ---\\\")\\n\",\n \" print(sorted(table_level_data[0].keys()))\\n\",\n \" \\n\",\n \" print(\\\"\\\\\\\\n--- Column-Level Entry Fields ---\\\") \\n\",\n \" print(sorted(sample_data[0].keys()))\\n\",\n \" \\n\",\n \" tl_keys = set(table_level_data[0].keys())\\n\",\n \" cl_keys = set(sample_data[0].keys())\\n\",\n \" \\n\",\n \" print(f\\\"\\\\\\\\nCommon fields: {tl_keys & cl_keys}\\\")\\n\",\n \" print(f\\\"Table-Level only: {tl_keys - cl_keys}\\\")\\n\",\n \" print(f\\\"Column-Level only: {cl_keys - tl_keys}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Table-level comparison - format verified compatible\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"7392ebc1\",\n \"metadata\": {},\n \"source\": [\n \"## 5. Role Generation Quality Assessment\\n\",\n \"\\n\",\n \"Automated quality checks for generated role files and RBAC datasets.\\n\",\n \"\\n\",\n \"### Quality Metrics\\n\",\n \"\\n\",\n \"| Metric | Healthy Range | Issue Description |\\n\",\n \"|--------|---------------|-------------------|\\n\",\n \"| **Deny Rate** | 5% - 90% | <5% too permissive, >90% too restrictive |\\n\",\n \"| **All-Allow Queries** | <50% | High value indicates poor role differentiation |\\n\",\n \"| **Role-Schema Similarity** | >0.6 | <0.6 indicates poor semantic alignment |\\n\",\n \"| **Policy Overlap** | <70% | >70% indicates redundant roles |\\n\",\n \"| **Coverage Diversity** | std >0.1 | Low std indicates roles have similar permissions |\\n\",\n \"\\n\",\n \"### Evaluation Pipeline\\n\",\n \"1. **Deny Rate Analysis**: Check permission distribution balance\\n\",\n \"2. **Semantic Quality**: Embedding-based role-schema alignment\\n\",\n \"3. **Policy Overlap**: Jaccard similarity to detect redundant roles\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"71f8f60f\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 5.1 Setup Quality Evaluator (force reload all modules)\\n\",\n \"import importlib\\n\",\n \"import sys\\n\",\n \"from pathlib import Path\\n\",\n \"import glob\\n\",\n \"\\n\",\n \"# Force reload the entire module tree\\n\",\n \"if 'src.role_evaluator.quality_metrics' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator.quality_metrics']\\n\",\n \"if 'src.role_evaluator.quality_visualizer' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator.quality_visualizer']\\n\",\n \"if 'src.role_evaluator' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator']\\n\",\n \"\\n\",\n \"from src.role_evaluator import RoleQualityEvaluator, RoleQualityVisualizer, print_quality_report\\n\",\n \"\\n\",\n \"# Configure paths\\n\",\n \"project_root = Path.cwd().parent if Path.cwd().name == 'notebooks' else Path.cwd()\\n\",\n \"\\n\",\n \"# Find most recent dataset and role assignments files\\n\",\n \"role_files = sorted(glob.glob(str(project_root / 'outputs' / 'column_level_role_assignments_bird_*.json')))\\n\",\n \"ROLE_ASSIGNMENTS_PATH = role_files[-1] if role_files else str(project_root / 'outputs' / 'column_level_role_assignments_bird.json')\\n\",\n \"\\n\",\n \"# Check for v2 role assignments (after regeneration)\\n\",\n \"role_files_v2 = sorted([f for f in glob.glob(str(project_root / 'outputs' / 'bird_column_level_rbac_assignments_*.json'))\\n\",\n \" if 'v2' in f])\\n\",\n \"if role_files_v2:\\n\",\n \" ROLE_ASSIGNMENTS_PATH = role_files_v2[-1]\\n\",\n \"\\n\",\n \"dataset_files = sorted([f for f in glob.glob(str(project_root / 'outputs' / 'column_level_rbac_dataset_bird_*.json')) \\n\",\n \" if 'metadata' not in f])\\n\",\n \"if not dataset_files:\\n\",\n \" raise FileNotFoundError(\\\"No RBAC dataset found in outputs/\\\")\\n\",\n \"DATASET_PATH = dataset_files[-1]\\n\",\n \"\\n\",\n \"SCHEMA_DIR = str(project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases')\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# CONFIGURABLE QUALITY THRESHOLDS\\n\",\n \"# Adjust based on dataset characteristics\\n\",\n \"# BIRD has larger DBs with more columns, so thresholds differ from Spider\\n\",\n \"# ============================================================\\n\",\n \"QUALITY_THRESHOLDS = {\\n\",\n \" \\\"deny_rate_min\\\": 5.0, # Warn if deny rate < this (roles too permissive)\\n\",\n \" \\\"coverage_max\\\": 0.85, # Warn if avg coverage > this (roles too broad)\\n\",\n \" \\\"coverage_std_min\\\": 0.065, # Warn if coverage std < this (low diversity)\\n\",\n \" \\\"max_overlap\\\": 0.80, # Warn if max overlap > this (redundant roles)\\n\",\n \"}\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EMBEDDING MODEL CONFIGURATION\\n\",\n \"# Backend auto-detected based on model name, or set explicitly\\n\",\n \"# ============================================================\\n\",\n \"# OpenAI models (requires OPENAI_API_KEY):\\n\",\n \"# - \\\"text-embedding-3-small\\\" (default, cost-effective)\\n\",\n \"# - \\\"text-embedding-3-large\\\" (higher accuracy)\\n\",\n \"# - \\\"text-embedding-ada-002\\\" (legacy)\\n\",\n \"# \\n\",\n \"# BAAI/fastembed models (local, no API key needed):\\n\",\n \"# - \\\"BAAI/bge-small-en-v1.5\\\" (fast, lightweight)\\n\",\n \"# - \\\"BAAI/bge-base-en-v1.5\\\" (balanced)\\n\",\n \"# - \\\"BAAI/bge-large-en-v1.5\\\" (best accuracy)\\n\",\n \"# ============================================================\\n\",\n \"# EMBED_MODEL = \\\"BAAI/bge-small-en-v1.5\\\"\\n\",\n \"EMBED_MODEL = \\\"text-embedding-3-small\\\"\\n\",\n \"EMBED_BACKEND = None # None = auto-detect, or \\\"openai\\\" / \\\"fastembed\\\"\\n\",\n \"\\n\",\n \"print(\\\"=== Quality Thresholds (Configurable for BIRD) ===\\\")\\n\",\n \"for k, v in QUALITY_THRESHOLDS.items():\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"print(f\\\" embed_model: {EMBED_MODEL}\\\")\\n\",\n \"print(f\\\" embed_backend: {EMBED_BACKEND or 'auto'}\\\")\\n\",\n \"\\n\",\n \"print(f\\\"\\\\nRole Assignments: {Path(ROLE_ASSIGNMENTS_PATH).name if ROLE_ASSIGNMENTS_PATH else 'Not found'}\\\")\\n\",\n \"print(f\\\"Dataset: {Path(DATASET_PATH).name if DATASET_PATH else 'Not found'}\\\")\\n\",\n \"print(f\\\"Schema Dir: {SCHEMA_DIR}\\\")\\n\",\n \"\\n\",\n \"if ROLE_ASSIGNMENTS_PATH and DATASET_PATH:\\n\",\n \" evaluator = RoleQualityEvaluator(\\n\",\n \" role_assignments_path=ROLE_ASSIGNMENTS_PATH,\\n\",\n \" dataset_path=DATASET_PATH,\\n\",\n \" schema_dir=SCHEMA_DIR,\\n\",\n \" embed_model=EMBED_MODEL,\\n\",\n \" embed_backend=EMBED_BACKEND,\\n\",\n \" thresholds=QUALITY_THRESHOLDS\\n\",\n \" )\\n\",\n \" print(\\\"\\\\n✓ Quality evaluator initialized with custom thresholds\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"\\\\n Missing files - generate roles and dataset first\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 74,\n \"id\": \"8135e2e3\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[embedding_utils] Using OpenAI embeddings (text-embedding-3-small) for 11 texts\\n\",\n \"[embedding_utils] Using OpenAI embeddings (text-embedding-3-small) for 47 texts\\n\",\n \"Overall: 11 databases, 53 roles, 7252 entries\\n\",\n \"Pass Rate: 100.0% (11/11 pass)\\n\",\n \"\\n\",\n \"Using Thresholds: deny_rate_min=5.0%, max_overlap=80%, coverage_std_min=0.065\\n\",\n \"\\n\",\n \"=== Deny Rate Analysis ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseDeny%AllAllow%AllDenyRolesStatus
0california_schools73.5%1.1%05OK
1card_games46.9%2.1%05OK
2codebase_community37.8%0.0%05OK
3debit_card_specializing54.7%0.0%06OK
4european_football_257.1%1.6%05OK
5financial70.6%0.0%05OK
6formula_144.7%8.7%04OK
7student_club49.9%1.3%05OK
8superhero49.1%0.0%05OK
9thrombosis_prediction33.7%2.5%04OK
10toxicology47.4%11.7%04OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Deny% AllAllow% AllDeny Roles Status\\n\",\n \"0 california_schools 73.5% 1.1% 0 5 OK\\n\",\n \"1 card_games 46.9% 2.1% 0 5 OK\\n\",\n \"2 codebase_community 37.8% 0.0% 0 5 OK\\n\",\n \"3 debit_card_specializing 54.7% 0.0% 0 6 OK\\n\",\n \"4 european_football_2 57.1% 1.6% 0 5 OK\\n\",\n \"5 financial 70.6% 0.0% 0 5 OK\\n\",\n \"6 formula_1 44.7% 8.7% 0 4 OK\\n\",\n \"7 student_club 49.9% 1.3% 0 5 OK\\n\",\n \"8 superhero 49.1% 0.0% 0 5 OK\\n\",\n \"9 thrombosis_prediction 33.7% 2.5% 0 4 OK\\n\",\n \"10 toxicology 47.4% 11.7% 0 4 OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Semantic Quality (Similarity: role-schema alignment, Coverage: column access, Diversity: coverage std) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseSimilarityCoverageDiversityStatus
0california_schools0.690234.8%0.0996OK
1card_games0.684350.0%0.2965OK
2codebase_community0.633260.6%0.2888OK
3debit_card_specializing0.626463.8%0.1299OK
4european_football_20.679931.3%0.0984OK
5financial0.641046.8%0.1288OK
6formula_10.659944.0%0.1480OK
7student_club0.678050.5%0.1701OK
8superhero0.683561.3%0.1895OK
9thrombosis_prediction0.660769.3%0.3798OK
10toxicology0.669869.7%0.1134OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Similarity Coverage Diversity Status\\n\",\n \"0 california_schools 0.6902 34.8% 0.0996 OK\\n\",\n \"1 card_games 0.6843 50.0% 0.2965 OK\\n\",\n \"2 codebase_community 0.6332 60.6% 0.2888 OK\\n\",\n \"3 debit_card_specializing 0.6264 63.8% 0.1299 OK\\n\",\n \"4 european_football_2 0.6799 31.3% 0.0984 OK\\n\",\n \"5 financial 0.6410 46.8% 0.1288 OK\\n\",\n \"6 formula_1 0.6599 44.0% 0.1480 OK\\n\",\n \"7 student_club 0.6780 50.5% 0.1701 OK\\n\",\n \"8 superhero 0.6835 61.3% 0.1895 OK\\n\",\n \"9 thrombosis_prediction 0.6607 69.3% 0.3798 OK\\n\",\n \"10 toxicology 0.6698 69.7% 0.1134 OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Policy Overlap Analysis ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseAvgOverlapMaxOverlapStatus
0california_schools30.7%57.1%OK
1card_games11.9%23.8%OK
2codebase_community28.0%57.8%OK
3debit_card_specializing47.0%65.0%OK
4european_football_214.4%23.8%OK
5financial21.5%37.0%OK
6formula_129.3%32.9%OK
7student_club30.2%45.0%OK
8superhero33.0%52.6%OK
9thrombosis_prediction18.1%38.5%OK
10toxicology53.7%66.7%OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database AvgOverlap MaxOverlap Status\\n\",\n \"0 california_schools 30.7% 57.1% OK\\n\",\n \"1 card_games 11.9% 23.8% OK\\n\",\n \"2 codebase_community 28.0% 57.8% OK\\n\",\n \"3 debit_card_specializing 47.0% 65.0% OK\\n\",\n \"4 european_football_2 14.4% 23.8% OK\\n\",\n \"5 financial 21.5% 37.0% OK\\n\",\n \"6 formula_1 29.3% 32.9% OK\\n\",\n \"7 student_club 30.2% 45.0% OK\\n\",\n \"8 superhero 33.0% 52.6% OK\\n\",\n \"9 thrombosis_prediction 18.1% 38.5% OK\\n\",\n \"10 toxicology 53.7% 66.7% OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n }\n ],\n \"source\": [\n \"# 5.2 Run Quality Evaluations and Display as DataFrame\\n\",\n \"import pandas as pd\\n\",\n \"import importlib\\n\",\n \"\\n\",\n \"# Force reload modules to use latest code\\n\",\n \"import src.role_evaluator.quality_metrics\\n\",\n \"import src.role_evaluator.quality_visualizer\\n\",\n \"importlib.reload(src.role_evaluator.quality_metrics)\\n\",\n \"importlib.reload(src.role_evaluator.quality_visualizer)\\n\",\n \"\\n\",\n \"from src.role_evaluator.quality_metrics import print_quality_report\\n\",\n \"\\n\",\n \"# Set display options for full content (no truncation)\\n\",\n \"pd.set_option('display.max_colwidth', None)\\n\",\n \"pd.set_option('display.max_rows', None)\\n\",\n \"pd.set_option('display.width', None)\\n\",\n \"\\n\",\n \"if 'evaluator' in dir():\\n\",\n \" report = evaluator.evaluate_all()\\n\",\n \" \\n\",\n \" # Summary\\n\",\n \" print(f\\\"Overall: {report.total_databases} databases, {report.total_roles} roles, {report.total_entries} entries\\\")\\n\",\n \" print(f\\\"Pass Rate: {report.pass_rate:.1%} ({report.total_databases - len(report.databases_with_issues)}/{report.total_databases} pass)\\\")\\n\",\n \" print(f\\\"\\\\nUsing Thresholds: deny_rate_min={QUALITY_THRESHOLDS['deny_rate_min']}%, \\\"\\n\",\n \" f\\\"max_overlap={QUALITY_THRESHOLDS['max_overlap']:.0%}, \\\"\\n\",\n \" f\\\"coverage_std_min={QUALITY_THRESHOLDS['coverage_std_min']}\\\\n\\\")\\n\",\n \" \\n\",\n \" # Deny Rate DataFrame - Full display\\n\",\n \" if report.deny_rate_metrics:\\n\",\n \" deny_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"Deny%\\\": f\\\"{m.deny_rate:.1f}%\\\",\\n\",\n \" \\\"AllAllow%\\\": f\\\"{m.all_allow_pct:.1f}%\\\",\\n\",\n \" \\\"AllDeny\\\": m.all_deny_queries,\\n\",\n \" \\\"Roles\\\": len(m.roles),\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.deny_rate_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"=== Deny Rate Analysis ===\\\")\\n\",\n \" display(deny_df)\\n\",\n \"\\n\",\n \" # Semantic Quality DataFrame \\n\",\n \" if report.semantic_metrics:\\n\",\n \" sem_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"Similarity\\\": f\\\"{m.avg_similarity:.4f}\\\",\\n\",\n \" \\\"Coverage\\\": f\\\"{m.avg_coverage:.1%}\\\",\\n\",\n \" \\\"Diversity\\\": f\\\"{m.coverage_std:.4f}\\\",\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.semantic_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Semantic Quality (Similarity: role-schema alignment, Coverage: column access, Diversity: coverage std) ===\\\")\\n\",\n \" display(sem_df)\\n\",\n \"\\n\",\n \" # Policy Overlap DataFrame\\n\",\n \" if report.overlap_metrics:\\n\",\n \" ovl_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"AvgOverlap\\\": f\\\"{m.avg_overlap:.1%}\\\",\\n\",\n \" \\\"MaxOverlap\\\": f\\\"{m.max_overlap:.1%}\\\",\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.overlap_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Policy Overlap Analysis ===\\\")\\n\",\n \" display(ovl_df)\\n\",\n \"else:\\n\",\n \" print(\\\" Evaluator not initialized\\\")\\n\",\n \"\\n\",\n \"pd.reset_option('display.max_colwidth')\\n\",\n \"pd.reset_option('display.max_rows')\\n\",\n \"pd.reset_option('display.width')\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 75,\n \"id\": \"89f843e7\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# # 5.3 Quality Dashboard Visualization\\n\",\n \"# import matplotlib.pyplot as plt\\n\",\n \"# from src.role_evaluator.quality_visualizer import RoleQualityVisualizer\\n\",\n \"\\n\",\n \"# visualizer = RoleQualityVisualizer(evaluator=evaluator, report=report)\\n\",\n \"# fig = visualizer.plot_quality_dashboard()\\n\",\n \"# plt.show()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"86eb26de\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 5.4 Semantic Alignment Visualization (Column-Level RBAC)\\n\",\n \"# Circle size = column coverage, Red triangles = SystemManager\\n\",\n \"import random\\n\",\n \"import math\\n\",\n \"import matplotlib.pyplot as plt\\n\",\n \"from matplotlib.colors import PowerNorm\\n\",\n \"from matplotlib import colormaps as cm\\n\",\n \"from collections import defaultdict\\n\",\n \"from matplotlib.lines import Line2D\\n\",\n \"import numpy as np\\n\",\n \"\\n\",\n \"sys.path.insert(0, str(project_root / \\\"plot\\\"))\\n\",\n \"from embedding_utils import cosine_similarity\\n\",\n \"\\n\",\n \"# Prepare records (recompute)\\n\",\n \"role_records = evaluator._prepare_role_records()\\n\",\n \"evaluator._compute_embeddings()\\n\",\n \"\\n\",\n \"# Build vis_records with is_system_manager\\n\",\n \"vis_records = []\\n\",\n \"for spec in role_records:\\n\",\n \" schema_emb = evaluator._schema_emb_dict.get(spec[\\\"schema_text\\\"])\\n\",\n \" role_emb = evaluator._role_emb_dict.get(spec[\\\"role_text\\\"])\\n\",\n \" \\n\",\n \" if schema_emb is not None and role_emb is not None:\\n\",\n \" raw_sim = cosine_similarity(role_emb, schema_emb)\\n\",\n \" similarity = max(0.0, min(1.0, (raw_sim + 1.0) / 2.0))\\n\",\n \" else:\\n\",\n \" similarity = 0.5\\n\",\n \" \\n\",\n \" total_cols = spec.get(\\\"total_columns\\\", 1)\\n\",\n \" accessible_cols = spec.get(\\\"accessible_columns\\\", 0)\\n\",\n \" col_coverage = accessible_cols / total_cols if total_cols > 0 else 0\\n\",\n \" \\n\",\n \" vis_records.append({\\n\",\n \" \\\"db_id\\\": spec[\\\"db_id\\\"],\\n\",\n \" \\\"role\\\": spec[\\\"role\\\"],\\n\",\n \" \\\"similarity\\\": similarity,\\n\",\n \" \\\"is_system_manager\\\": spec.get(\\\"is_system_manager\\\", False),\\n\",\n \" \\\"column_coverage\\\": col_coverage,\\n\",\n \" })\\n\",\n \"\\n\",\n \"sm_count = sum(1 for r in vis_records if r[\\\"is_system_manager\\\"])\\n\",\n \"print(f\\\"Total roles: {len(vis_records)}, SystemManager: {sm_count}\\\")\\n\",\n \"\\n\",\n \"# Plot function\\n\",\n \"def plot_semantic(records, output_path, title, dbs_per_panel=12):\\n\",\n \" db_to_entries = defaultdict(list)\\n\",\n \" sims = []\\n\",\n \" for rec in records:\\n\",\n \" sims.append(rec[\\\"similarity\\\"])\\n\",\n \" size = 90.0 + rec[\\\"column_coverage\\\"] * 220.0\\n\",\n \" db_to_entries[rec[\\\"db_id\\\"]].append({\\n\",\n \" \\\"sim\\\": rec[\\\"similarity\\\"], \\\"size\\\": size,\\n\",\n \" \\\"is_sm\\\": rec[\\\"is_system_manager\\\"],\\n\",\n \" })\\n\",\n \" \\n\",\n \" db_ids = sorted(db_to_entries.keys())\\n\",\n \" panels = [db_ids[i:i+dbs_per_panel] for i in range(0, len(db_ids), dbs_per_panel)]\\n\",\n \" \\n\",\n \" min_s, max_s = min(sims), max(sims)\\n\",\n \" if math.isclose(min_s, max_s): max_s = min_s + 1e-6\\n\",\n \" span = max_s - min_s\\n\",\n \" norm = PowerNorm(gamma=0.55, vmin=min_s, vmax=max_s)\\n\",\n \" cmap = cm[\\\"viridis\\\"]\\n\",\n \" \\n\",\n \" fig = plt.figure(figsize=(11, sum(0.35*len(p)+0.6 for p in panels)+2))\\n\",\n \" gs = fig.add_gridspec(len(panels), 1, height_ratios=[0.35*len(p)+0.6 for p in panels], hspace=0.18)\\n\",\n \" axes = []\\n\",\n \" \\n\",\n \" random.seed(42)\\n\",\n \" sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)\\n\",\n \" sm.set_array([])\\n\",\n \" \\n\",\n \" for pi, chunk in enumerate(panels):\\n\",\n \" ax = fig.add_subplot(gs[pi, 0])\\n\",\n \" axes.append(ax)\\n\",\n \" for ri, db in enumerate(chunk):\\n\",\n \" y = float(ri)\\n\",\n \" ax.axhline(y, color=\\\"#d0d0d0\\\", linestyle=\\\"--\\\", lw=0.9, zorder=0)\\n\",\n \" for e in db_to_entries[db]:\\n\",\n \" x = (e[\\\"sim\\\"] - min_s) / span + random.uniform(-0.012, 0.012)\\n\",\n \" if e[\\\"is_sm\\\"]:\\n\",\n \" ax.scatter(x, y, s=250, c=\\\"#d62728\\\", alpha=0.95,\\n\",\n \" edgecolors=\\\"#8c1c15\\\", lw=1.0, marker=\\\"^\\\", zorder=4)\\n\",\n \" else:\\n\",\n \" ax.scatter(x, y + random.uniform(-0.16, 0.16), s=e[\\\"size\\\"]*2.5,\\n\",\n \" c=[e[\\\"sim\\\"]], cmap=cmap, norm=norm, alpha=0.82,\\n\",\n \" edgecolors=\\\"#333\\\", lw=0.45, marker=\\\"o\\\")\\n\",\n \" ax.set_yticks(range(len(chunk)))\\n\",\n \" ax.set_yticklabels(chunk, fontsize=10, weight='bold')\\n\",\n \" ax.set_xlim(-0.05, 1.05)\\n\",\n \" ax.set_ylim(-0.6, len(chunk)-0.4)\\n\",\n \" ax.set_xticks(np.linspace(0, 1, 5))\\n\",\n \" ax.set_xticklabels([f\\\"{min_s + p*span:.2f}\\\" for p in np.linspace(0,1,5)], fontsize=9)\\n\",\n \" ax.grid(axis=\\\"x\\\", ls=\\\":\\\", lw=0.5, alpha=0.45)\\n\",\n \" \\n\",\n \" axes[-1].set_xlabel(\\\"Semantic similarity\\\", fontsize=12, weight='bold')\\n\",\n \" fig.suptitle(f\\\"{title}: Role-Schema Alignment\\\", fontsize=14, y=0.98, weight='bold')\\n\",\n \" cbar = fig.colorbar(sm, ax=axes, fraction=0.03, pad=0.015)\\n\",\n \" cbar.set_label(\\\"Similarity\\\", fontsize=10)\\n\",\n \" \\n\",\n \" legend = [\\n\",\n \" Line2D([0],[0], marker='^', color='w', markerfacecolor='#d62728',\\n\",\n \" markeredgecolor='#8c1c15', markersize=12, label='SystemManager'),\\n\",\n \" Line2D([0],[0], marker='o', color='w', markerfacecolor='#21918c',\\n\",\n \" markeredgecolor='#333', markersize=8, label='Other (size=col coverage)'),\\n\",\n \" ]\\n\",\n \" fig.legend(handles=legend, loc='upper right', fontsize=9)\\n\",\n \" plt.tight_layout(rect=[0,0,0.95,0.95])\\n\",\n \" fig.savefig(output_path, dpi=150, bbox_inches='tight')\\n\",\n \" plt.close(fig)\\n\",\n \" print(f\\\"Saved: {output_path}\\\")\\n\",\n \"\\n\",\n \"output_path = project_root / \\\"plot\\\" / \\\"column_level_rbac_semantic.png\\\"\\n\",\n \"plot_semantic(vis_records, output_path, \\\"Column-Level RBAC (BIRD)\\\")\\n\",\n \"from IPython.display import Image, display\\n\",\n \"display(Image(filename=str(output_path)))\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 13,\n \"id\": \"2dd807b4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Databases Requiring Review (1/11) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseDeny%AllAllow%CoverageCovStdMaxOverlapIssues
0california_schools63.1%5.6%50.8%0.05972.3%all-deny queries found (1) - SystemManager coverage broken; Low role diversity
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Deny% AllAllow% Coverage CovStd MaxOverlap \\\\\\n\",\n \"0 california_schools 63.1% 5.6% 50.8% 0.059 72.3% \\n\",\n \"\\n\",\n \" Issues \\n\",\n \"0 all-deny queries found (1) - SystemManager coverage broken; Low role diversity \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"Issue Thresholds:\\n\",\n \" - Deny% < 5%: roles too permissive\\n\",\n \" - Coverage > 85%: most roles have near-full access\\n\",\n \" - CovStd < 0.065: roles have similar coverage (low diversity)\\n\",\n \" - MaxOverlap >80%: redundant roles with similar policies\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 5.5 Export Problematic Databases as DataFrame\\n\",\n \"if report.databases_with_issues:\\n\",\n \" issues_data = []\\n\",\n \" for db_id in report.databases_with_issues:\\n\",\n \" row = {\\\"Database\\\": db_id}\\n\",\n \" \\n\",\n \" if db_id in report.deny_rate_metrics:\\n\",\n \" m = report.deny_rate_metrics[db_id]\\n\",\n \" row[\\\"Deny%\\\"] = f\\\"{m.deny_rate:.1f}%\\\"\\n\",\n \" row[\\\"AllAllow%\\\"] = f\\\"{m.all_allow_pct:.1f}%\\\"\\n\",\n \" \\n\",\n \" if db_id in report.semantic_metrics:\\n\",\n \" m = report.semantic_metrics[db_id]\\n\",\n \" row[\\\"Coverage\\\"] = f\\\"{m.avg_coverage:.1%}\\\" # Source of \\\"Most roles too permissive\\\" (>90%)\\n\",\n \" row[\\\"CovStd\\\"] = f\\\"{m.coverage_std:.3f}\\\" # Source of \\\"Low role diversity\\\" (<0.1)\\n\",\n \" \\n\",\n \" if db_id in report.overlap_metrics:\\n\",\n \" m = report.overlap_metrics[db_id]\\n\",\n \" row[\\\"MaxOverlap\\\"] = f\\\"{m.max_overlap:.1%}\\\" # Source of \\\"High max overlap\\\" (>70%)\\n\",\n \" \\n\",\n \" row[\\\"Issues\\\"] = \\\"; \\\".join(report.all_issues.get(db_id, []))\\n\",\n \" issues_data.append(row)\\n\",\n \" \\n\",\n \" issues_df = pd.DataFrame(issues_data)\\n\",\n \" print(f\\\"=== Databases Requiring Review ({len(issues_df)}/{report.total_databases}) ===\\\")\\n\",\n \" \\n\",\n \" # Display with full column width for Issues column\\n\",\n \" pd.set_option('display.max_colwidth', None)\\n\",\n \" pd.set_option('display.max_rows', None)\\n\",\n \" display(issues_df)\\n\",\n \" pd.reset_option('display.max_colwidth')\\n\",\n \" pd.reset_option('display.max_rows')\\n\",\n \" \\n\",\n \" print(\\\"\\\\nIssue Thresholds:\\\")\\n\",\n \" print(\\\" - Deny% < 5%: roles too permissive\\\")\\n\",\n \" print(\\\" - Coverage > 85%: most roles have near-full access\\\")\\n\",\n \" print(\\\" - CovStd < 0.065: roles have similar coverage (low diversity)\\\")\\n\",\n \" print(\\\" - MaxOverlap >80%: redundant roles with similar policies\\\")\\n\",\n \"\\n\",\n \"else:\\n\",\n \" print(\\\"[OK] All databases pass quality checks!\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"7586c455\",\n \"metadata\": {},\n \"source\": [\n \"## 6. Regenerate Roles for Problematic Databases\\n\",\n \"\\n\",\n \"Human-in-the-loop workflow for fixing quality issues:\\n\",\n \"\\n\",\n \"| Step | Cell | Description |\\n\",\n \"|------|------|-------------|\\n\",\n \"| 1 | 6.1 | Select database, view schema and current roles |\\n\",\n \"| 2 | 6.2 | Write regeneration hints (edit manually) |\\n\",\n \"| 3 | 6.3 | Execute regeneration with LLM |\\n\",\n \"| 4 | 6.4 | Preview and compare OLD vs NEW |\\n\",\n \"| 5 | 6.4.1 | Select & combine roles from OLD and NEW |\\n\",\n \"| 6 | 6.5 | Apply changes if satisfied |\\n\",\n \"| 7 | 6.6 | Regenerate RBAC Dataset with updated roles |\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 32,\n \"id\": \"70f25858\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"Database: formula_1\\n\",\n \"======================================================================\\n\",\n \"\\n\",\n \"=== Schema (13 tables, 94 columns) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
TableColumnTypePKFK
0circuitscircuitIdINTEGERYes
1circuitscircuitRefTEXT
2circuitsnameTEXT
3circuitslocationTEXT
4circuitscountryTEXT
..................
89resultsfastestLapINTEGER
90resultsrankINTEGER
91resultsfastestLapTimeTEXT
92resultsfastestLapSpeedTEXT
93resultsstatusIdINTEGERstatus.statusId
\\n\",\n \"

94 rows × 5 columns

\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Table Column Type PK FK\\n\",\n \"0 circuits circuitId INTEGER Yes \\n\",\n \"1 circuits circuitRef TEXT \\n\",\n \"2 circuits name TEXT \\n\",\n \"3 circuits location TEXT \\n\",\n \"4 circuits country TEXT \\n\",\n \".. ... ... ... ... ...\\n\",\n \"89 results fastestLap INTEGER \\n\",\n \"90 results rank INTEGER \\n\",\n \"91 results fastestLapTime TEXT \\n\",\n \"92 results fastestLapSpeed TEXT \\n\",\n \"93 results statusId INTEGER status.statusId\\n\",\n \"\\n\",\n \"[94 rows x 5 columns]\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Current Roles (5) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
RoleDescriptionTablesColumnsPolicy
0RaceAnalystAnalyzes race performance data including lap times, pit stops, and qualifying results965 (*)circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date, time]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]; status: [statusId, status]
1StandingsManagerManages championship standings and constructor/driver points calculations743 (*)constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; results: [resultId, raceId, driverId, constructorId, position, positionOrder, points]
2MediaCoordinatorProvides public information for media and fan engagement633 (*)circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, constructorRef, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [*]; races: [raceId, year, round, circuitId, name, date, time, url]; status: [statusId, status]
3DriverManagerManages driver information and personal details including date of birth432 (*)drivers: [*]; races: [raceId, year, round, name, date]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, statusId]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]
4SystemManagerFull administrative access for system maintenance and data integrity1394 (*)circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*]
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Role \\\\\\n\",\n \"0 RaceAnalyst \\n\",\n \"1 StandingsManager \\n\",\n \"2 MediaCoordinator \\n\",\n \"3 DriverManager \\n\",\n \"4 SystemManager \\n\",\n \"\\n\",\n \" Description \\\\\\n\",\n \"0 Analyzes race performance data including lap times, pit stops, and qualifying results \\n\",\n \"1 Manages championship standings and constructor/driver points calculations \\n\",\n \"2 Provides public information for media and fan engagement \\n\",\n \"3 Manages driver information and personal details including date of birth \\n\",\n \"4 Full administrative access for system maintenance and data integrity \\n\",\n \"\\n\",\n \" Tables Columns \\\\\\n\",\n \"0 9 65 (*) \\n\",\n \"1 7 43 (*) \\n\",\n \"2 6 33 (*) \\n\",\n \"3 4 32 (*) \\n\",\n \"4 13 94 (*) \\n\",\n \"\\n\",\n \" Policy \\n\",\n \"0 circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date, time]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]; status: [statusId, status] \\n\",\n \"1 constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; results: [resultId, raceId, driverId, constructorId, position, positionOrder, points] \\n\",\n \"2 circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, constructorRef, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [*]; races: [raceId, year, round, circuitId, name, date, time, url]; status: [statusId, status] \\n\",\n \"3 drivers: [*]; races: [raceId, year, round, name, date]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, statusId]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins] \\n\",\n \"4 circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*] \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Role x Table Matrix (column counts, * expanded) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
TablecircuitsconstructorResultsconstructorStandingsconstructorsdriverStandingsdriverslapTimespitStopsqualifyingracesresultsseasonsstatus
Role             
DriverManager0.0000000.0000000.0000000.0000007.0000009.0000000.0000000.0000000.0000005.00000011.0000000.0000000.000000
MediaCoordinator8.0000000.0000000.0000005.0000000.0000008.0000000.0000000.0000000.0000008.0000000.0000002.0000002.000000
RaceAnalyst6.0000000.0000000.0000004.0000000.0000007.0000006.0000007.0000009.0000007.00000017.0000000.0000002.000000
StandingsManager0.0000005.0000007.0000004.0000007.0000007.0000000.0000000.0000000.0000006.0000007.0000000.0000000.000000
SystemManager9.0000005.0000007.0000005.0000007.0000009.0000006.0000007.0000009.0000008.00000018.0000002.0000002.000000
\\n\"\n ],\n \"text/plain\": [\n \"\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"[SUMMARY] 1 database(s) selected: ['formula_1']\\n\",\n \"[NEXT] Edit hints in Cell 6.2, then run Cell 6.3\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.1 Select Database(s) & View Current State\\n\",\n \"# Supports single db (str) or multiple dbs (list)\\n\",\n \"\\n\",\n \"TARGET_DBS = [\\\"formula_1\\\"] # Single: \\\"toxicology\\\" or Multiple: [\\\"toxicology\\\", \\\"california_schools\\\"]\\n\",\n \"\\n\",\n \"# Normalize to list\\n\",\n \"if isinstance(TARGET_DBS, str):\\n\",\n \" TARGET_DBS = [TARGET_DBS]\\n\",\n \"\\n\",\n \"# Load current role assignments\\n\",\n \"with open(ROLE_ASSIGNMENTS_PATH, 'r') as f:\\n\",\n \" all_assignments = json.load(f)\\n\",\n \"\\n\",\n \"available_dbs = set(all_assignments.get('assignments', {}).keys())\\n\",\n \"valid_target_dbs = [db for db in TARGET_DBS if db in available_dbs]\\n\",\n \"invalid_dbs = [db for db in TARGET_DBS if db not in available_dbs]\\n\",\n \"\\n\",\n \"if invalid_dbs:\\n\",\n \" print(f\\\"[WARN] Databases not found: {invalid_dbs}\\\")\\n\",\n \" print(f\\\"Available: {sorted(available_dbs)}\\\\n\\\")\\n\",\n \"\\n\",\n \"# Store schemas for later use\\n\",\n \"target_schemas = {}\\n\",\n \"\\n\",\n \"for TARGET_DB in valid_target_dbs:\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"Database: {TARGET_DB}\\\")\\n\",\n \" print(f\\\"{'='*70}\\\")\\n\",\n \" \\n\",\n \" # --- Schema Summary ---\\n\",\n \" db_path = bird_db_dir / TARGET_DB / f\\\"{TARGET_DB}.sqlite\\\"\\n\",\n \" if db_path.exists():\\n\",\n \" target_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" target_schemas[TARGET_DB] = target_schema\\n\",\n \" \\n\",\n \" schema_rows = []\\n\",\n \" for table, info in target_schema.items():\\n\",\n \" for col in info['columns']:\\n\",\n \" schema_rows.append({\\n\",\n \" \\\"Table\\\": table,\\n\",\n \" \\\"Column\\\": col['name'],\\n\",\n \" \\\"Type\\\": col['type'],\\n\",\n \" \\\"PK\\\": \\\"Yes\\\" if col['pk'] else \\\"\\\",\\n\",\n \" \\\"FK\\\": col.get('fk', '') or \\\"\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" schema_df = pd.DataFrame(schema_rows)\\n\",\n \" print(f\\\"\\\\n=== Schema ({len(target_schema)} tables, {len(schema_df)} columns) ===\\\")\\n\",\n \" display(schema_df)\\n\",\n \" else:\\n\",\n \" print(f\\\"[ERROR] Database not found: {db_path}\\\")\\n\",\n \" target_schemas[TARGET_DB] = None\\n\",\n \" continue\\n\",\n \"\\n\",\n \" # --- Current Roles ---\\n\",\n \" if TARGET_DB in all_assignments.get('assignments', {}):\\n\",\n \" current_roles = all_assignments['assignments'][TARGET_DB]\\n\",\n \" \\n\",\n \" # Set display options for full content\\n\",\n \" pd.set_option('display.max_colwidth', None)\\n\",\n \" \\n\",\n \" roles_rows = []\\n\",\n \" for role_info in current_roles:\\n\",\n \" policy = role_info.get('policy', {})\\n\",\n \" total_access = count_policy_columns(policy, target_schema)\\n\",\n \" has_wildcard = has_wildcard_policy(policy)\\n\",\n \" cols_display = f\\\"{total_access}\\\" + (\\\" (*)\\\" if has_wildcard else \\\"\\\")\\n\",\n \" # Full policy string\\n\",\n \" policy_str = \\\"; \\\".join([\\n\",\n \" f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" \\n\",\n \" for t, c in policy.items()\\n\",\n \" ])\\n\",\n \" roles_rows.append({\\n\",\n \" \\\"Role\\\": role_info['role'],\\n\",\n \" \\\"Description\\\": role_info.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Columns\\\": cols_display,\\n\",\n \" \\\"Policy\\\": policy_str\\n\",\n \" })\\n\",\n \" \\n\",\n \" roles_df = pd.DataFrame(roles_rows)\\n\",\n \" print(f\\\"\\\\n=== Current Roles ({len(current_roles)}) ===\\\")\\n\",\n \" display(roles_df)\\n\",\n \" \\n\",\n \" pd.reset_option('display.max_colwidth')\\n\",\n \" \\n\",\n \" # Policy detail matrix\\n\",\n \" policy_rows = []\\n\",\n \" for role_info in current_roles:\\n\",\n \" policy = role_info.get('policy', {})\\n\",\n \" for table, cols in policy.items():\\n\",\n \" num_cols = count_policy_columns({table: cols}, target_schema)\\n\",\n \" policy_rows.append({\\n\",\n \" \\\"Role\\\": role_info['role'],\\n\",\n \" \\\"Table\\\": table,\\n\",\n \" \\\"NumCols\\\": num_cols\\n\",\n \" })\\n\",\n \" \\n\",\n \" if policy_rows:\\n\",\n \" policy_df = pd.DataFrame(policy_rows)\\n\",\n \" pivot = policy_df.pivot_table(index='Role', columns='Table', values='NumCols', fill_value=0)\\n\",\n \" print(\\\"\\\\n=== Role x Table Matrix (column counts, * expanded) ===\\\")\\n\",\n \" display(pivot.style.background_gradient(cmap='Blues', axis=None))\\n\",\n \" \\n\",\n \" # Quality issues\\n\",\n \" if 'report' in dir() and TARGET_DB in report.all_issues:\\n\",\n \" print(f\\\"\\\\n=== Quality Issues ===\\\")\\n\",\n \" issues = report.all_issues[TARGET_DB]\\n\",\n \" if TARGET_DB in report.deny_rate_metrics:\\n\",\n \" m = report.deny_rate_metrics[TARGET_DB]\\n\",\n \" issues_df = pd.DataFrame([{\\n\",\n \" \\\"Deny Rate\\\": f\\\"{m.deny_rate:.1f}%\\\",\\n\",\n \" \\\"All-Allow %\\\": f\\\"{m.all_allow_pct:.1f}%\\\",\\n\",\n \" \\\"Issues\\\": \\\"; \\\".join(issues)\\n\",\n \" }])\\n\",\n \" display(issues_df)\\n\",\n \" else:\\n\",\n \" print(f\\\"[ERROR] No roles found for {TARGET_DB}\\\")\\n\",\n \"\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"[SUMMARY] {len(valid_target_dbs)} database(s) selected: {valid_target_dbs}\\\")\\n\",\n \" print(\\\"[NEXT] Edit hints in Cell 6.2, then run Cell 6.3\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[INFO] No databases selected. Edit TARGET_DBS above and re-run.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 34,\n \"id\": \"f8416bc4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Applying shared hint to 1 database(s) ===\\n\",\n \"\\n\",\n \" ✓ formula_1: 13 tables, 94 columns\\n\",\n \"\\n\",\n \"[NEXT] Run Cell 6.3 to regenerate all 1 database(s)\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.2 Write Regeneration Hints (Human-in-the-Loop)\\n\",\n \"# Write ONE shared hint for all selected databases (they have similar issues)\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EDIT HERE: Shared problem description for all selected DBs\\n\",\n \"# Supports {db}, {num_tables}, {num_cols} placeholders\\n\",\n \"# ============================================================\\n\",\n \"# PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"# [PROBLEM]\\n\",\n \"# Low deny rate - almost all queries are allowed by all roles (roles too permissive)\\n\",\n \"# Low diversity - all roles have similar access patterns (coverage_std too low)\\n\",\n \"\\n\",\n \"\\n\",\n \"# [ROOT CAUSE]\\n\",\n \"# - Most roles can access most/all columns, so very few queries get denied\\n\",\n \"# - This defeats the purpose of RBAC - no meaningful access control\\n\",\n \"\\n\",\n \"# [DIRECTION]\\n\",\n \"# - Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"# - Create restrictive roles that only access specific subsets of data\\n\",\n \"# - Each role should have a clear, limited scope\\n\",\n \"# - Some roles should be restricted to fewer tables\\n\",\n \"# - Do not frequently giving non-admin roles \\\"*\\\" (all columns) access\\n\",\n \"# - Create clear functional boundaries between roles\\n\",\n \"# \\\"\\\"\\\"\\n\",\n \"\\n\",\n \"# All-denied cases - even SystemManager role cannot access some columns\\n\",\n \"# - Ensure SystemManager role has full access to all tables and columns\\n\",\n \"\\n\",\n \"\\n\",\n \"PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"[PROBLEM]\\n\",\n \"Low semantic alignment - roles do not align well with schema\\n\",\n \"All-denied cases - even SystemManager role cannot access some columns\\n\",\n \"\\n\",\n \"[ROOT CAUSE]\\n\",\n \"- This defeats the purpose of RBAC - no meaningful access control\\n\",\n \"\\n\",\n \"[DIRECTION]\\n\",\n \"- Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"- Ensure SystemManager role has full access to all tables and columns\\n\",\n \"- Review other roles to ensure they align with specific functional areas\\n\",\n \"- Each role should have a clear, limited scope\\n\",\n \"- Create meaningful semantic role names and descriptions that reflect their access patterns\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"# PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"# [PROBLEM]\\n\",\n \"# Low diversity - all roles have similar access patterns (coverage_std too low)\\n\",\n \"\\n\",\n \"# [ROOT CAUSE]\\n\",\n \"# - This defeats the purpose of RBAC - no meaningful access control differentiation\\n\",\n \"\\n\",\n \"# [DIRECTION]\\n\",\n \"# - Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"# - Create restrictive roles that only access specific subsets of data\\n\",\n \"# - Each role should have a clear, limited scope\\n\",\n \"# - Some roles should be restricted to fewer tables\\n\",\n \"# - Do not frequently giving non-admin roles \\\"*\\\" (all columns) access\\n\",\n \"# - Create clear functional boundaries between roles\\n\",\n \"# \\\"\\\"\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# Auto-apply to all selected databases (no need to edit below)\\n\",\n \"# ============================================================\\n\",\n \"REGENERATION_HINTS = {}\\n\",\n \"\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"=== Applying shared hint to {len(valid_target_dbs)} database(s) ===\\\\n\\\")\\n\",\n \" for db in valid_target_dbs:\\n\",\n \" schema = target_schemas.get(db, {})\\n\",\n \" num_tables = len(schema)\\n\",\n \" num_cols = sum(len(t['columns']) for t in schema.values())\\n\",\n \" \\n\",\n \" # Fill placeholders\\n\",\n \" REGENERATION_HINTS[db] = PROBLEM_TO_FIX.format(\\n\",\n \" db=db, num_tables=num_tables, num_cols=num_cols\\n\",\n \" )\\n\",\n \" print(f\\\" ✓ {db}: {num_tables} tables, {num_cols} columns\\\")\\n\",\n \"\\n\",\n \" print(f\\\"\\\\n[NEXT] Run Cell 6.3 to regenerate all {len(valid_target_dbs)} database(s)\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[INFO] No databases selected. Run Cell 6.1 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 68,\n \"id\": \"91109a7c\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Regenerating roles for 1 database(s)...\\n\",\n \"============================================================\\n\",\n \"\\n\",\n \"[formula_1] Generating...\\n\",\n \" ✓ 5 roles (5 valid)\\n\",\n \"\\n\",\n \"============================================================\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseStatusRolesValidTokens
0formula_1success553058
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Status Roles Valid Tokens\\n\",\n \"0 formula_1 success 5 5 3058\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"[OK] All databases regenerated. Run Cell 6.4 to preview.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.3 Execute Regeneration with Hints (supports multiple databases)\\n\",\n \"\\n\",\n \"def regenerate_single_database(db_name: str, hint: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Regenerate roles for a single database with guidance hints.\\\"\\\"\\\"\\n\",\n \" db_path = bird_db_dir / db_name / f\\\"{db_name}.sqlite\\\"\\n\",\n \" \\n\",\n \" if not db_path.exists():\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": \\\"Database not found\\\"}\\n\",\n \" \\n\",\n \" try:\\n\",\n \" db_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" db_schema_text = format_schema_for_prompt(db_schema, db_name)\\n\",\n \" \\n\",\n \" enhanced_system_prompt = f\\\"{COLUMN_LEVEL_SYSTEM_PROMPT}\\\\n\\\\n[OPTIMIZATION GUIDANCE]\\\\n{hint}\\\"\\n\",\n \" user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=db_schema_text)\\n\",\n \" \\n\",\n \" response = oracle.query(\\n\",\n \" prompt_sys=enhanced_system_prompt,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3,\\n\",\n \" top_p=0.9,\\n\",\n \" max_completion_tokens=DEFAULT_MAX_TOKENS\\n\",\n \" )\\n\",\n \" \\n\",\n \" llm_response = response['answer']\\n\",\n \" usage = response.get('usage', {})\\n\",\n \" roles = parse_column_level_roles(llm_response)\\n\",\n \" \\n\",\n \" if not roles:\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"parse_error\\\", \\n\",\n \" \\\"error\\\": \\\"Failed to parse LLM response\\\", \\\"raw_response\\\": llm_response[:500]}\\n\",\n \" \\n\",\n \" validation = validate_roles_against_schema(roles, str(db_path))\\n\",\n \" assignments = [{\\\"role\\\": r[\\\"role\\\"], \\\"description\\\": r.get(\\\"description\\\", \\\"\\\"), \\n\",\n \" \\\"policy\\\": r.get(\\\"columns\\\", {})} for r in roles]\\n\",\n \" \\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"success\\\", \\\"roles_count\\\": len(assignments),\\n\",\n \" \\\"valid_roles\\\": validation['valid_roles'], \\\"all_valid\\\": validation['all_valid'],\\n\",\n \" \\\"assignments\\\": assignments, \\\"usage\\\": usage, \\\"raw_response\\\": llm_response}\\n\",\n \" except Exception as e:\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": str(e)}\\n\",\n \"\\n\",\n \"# Execute for all target databases\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"Regenerating roles for {len(valid_target_dbs)} database(s)...\\\")\\n\",\n \" print(\\\"=\\\"*60)\\n\",\n \"\\n\",\n \" regenerated_results = {} # Store all results\\n\",\n \" all_success = True\\n\",\n \"\\n\",\n \" for db_name in valid_target_dbs:\\n\",\n \" hint = REGENERATION_HINTS.get(db_name, PROBLEM_TO_FIX)\\n\",\n \" print(f\\\"\\\\n[{db_name}] Generating...\\\")\\n\",\n \" \\n\",\n \" result = regenerate_single_database(db_name, hint)\\n\",\n \" regenerated_results[db_name] = result\\n\",\n \" \\n\",\n \" if result[\\\"status\\\"] == \\\"success\\\":\\n\",\n \" print(f\\\" ✓ {result['roles_count']} roles ({result['valid_roles']} valid)\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" ✗ {result.get('error', result['status'])}\\\")\\n\",\n \" all_success = False\\n\",\n \"\\n\",\n \" # Summary table\\n\",\n \" print(\\\"\\\\n\\\" + \\\"=\\\"*60)\\n\",\n \" result_df = pd.DataFrame([{\\n\",\n \" \\\"Database\\\": r[\\\"database\\\"],\\n\",\n \" \\\"Status\\\": r[\\\"status\\\"],\\n\",\n \" \\\"Roles\\\": r.get(\\\"roles_count\\\", \\\"N/A\\\"),\\n\",\n \" \\\"Valid\\\": r.get(\\\"valid_roles\\\", \\\"N/A\\\"),\\n\",\n \" \\\"Tokens\\\": r.get(\\\"usage\\\", {}).get(\\\"total_tokens\\\", \\\"N/A\\\")\\n\",\n \" } for r in regenerated_results.values()])\\n\",\n \" display(result_df)\\n\",\n \"\\n\",\n \" if all_success:\\n\",\n \" print(\\\"\\\\n[OK] All databases regenerated. Run Cell 6.4 to preview.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"\\\\n[WARN] Some databases failed. Check errors above.\\\")\\n\",\n \"else:\\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"[INFO] No databases selected. Run Cell 6.1 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 69,\n \"id\": \"a2b0ba98\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"Database: formula_1\\n\",\n \"======================================================================\\n\",\n \"\\n\",\n \"=== NEW Roles (5) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
RoleDescriptionTablesColsPolicy
0SystemManagerFull administrative access for system maintenance and data management1394 (*)circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*]
1RaceAnalystAnalyzes race performance data including lap times, pit stops, and qualifying results861circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; lapTimes: [raceId, driverId, lap, position, time, milliseconds]; pitStops: [raceId, driverId, stop, lap, time, duration, milliseconds]; qualifying: [qualifyId, raceId, driverId, constructorId, number, position, q1, q2, q3]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]
2StandingsManagerManages and monitors championship standings for drivers and constructors742constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, name, date]; constructorResults: [constructorResultsId, raceId, constructorId, points, status]; constructorStandings: [constructorStandingsId, raceId, constructorId, points, position, positionText, wins]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, points, position, positionText, statusId]
3PublicRelationsAccesses public information about circuits, drivers, constructors, and race schedules631circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [year, url]; races: [raceId, year, round, circuitId, name, date, url]; status: [statusId, status]
4DriverManagerManages driver information and personal details including date of birth432drivers: [driverId, driverRef, number, code, forename, surname, dob, nationality]; races: [raceId, year, round, name, date]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionText, positionOrder, points, laps, statusId]
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Role \\\\\\n\",\n \"0 SystemManager \\n\",\n \"1 RaceAnalyst \\n\",\n \"2 StandingsManager \\n\",\n \"3 PublicRelations \\n\",\n \"4 DriverManager \\n\",\n \"\\n\",\n \" Description \\\\\\n\",\n \"0 Full administrative access for system maintenance and data management \\n\",\n \"1 Analyzes race performance data including lap times, pit stops, and qualifying results \\n\",\n \"2 Manages and monitors championship standings for drivers and constructors \\n\",\n \"3 Accesses public information about circuits, drivers, constructors, and race schedules \\n\",\n \"4 Manages driver information and personal details including date of birth \\n\",\n \"\\n\",\n \" Tables Cols \\\\\\n\",\n \"0 13 94 (*) \\n\",\n \"1 8 61 \\n\",\n \"2 7 42 \\n\",\n \"3 6 31 \\n\",\n \"4 4 32 \\n\",\n \"\\n\",\n \" Policy \\n\",\n \"0 circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*] \\n\",\n \"1 circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; lapTimes: [raceId, driverId, lap, position, time, milliseconds]; pitStops: [raceId, driverId, stop, lap, time, duration, milliseconds]; qualifying: [qualifyId, raceId, driverId, constructorId, number, position, q1, q2, q3]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId] \\n\",\n \"2 constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, name, date]; constructorResults: [constructorResultsId, raceId, constructorId, points, status]; constructorStandings: [constructorStandingsId, raceId, constructorId, points, position, positionText, wins]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, points, position, positionText, statusId] \\n\",\n \"3 circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [year, url]; races: [raceId, year, round, circuitId, name, date, url]; status: [statusId, status] \\n\",\n \"4 drivers: [driverId, driverRef, number, code, forename, surname, dob, nationality]; races: [raceId, year, round, name, date]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionText, positionOrder, points, laps, statusId] \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Quality Comparison ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
MetricOLDNEWThresholdStatus
0Roles55NaNNaN
1Avg Coverage65.5%55.3%<85%OK
2Coverage Std0.1830.251>0.065OK
3Max Overlap87.3%57.4%<80%OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Metric OLD NEW Threshold Status\\n\",\n \"0 Roles 5 5 NaN NaN\\n\",\n \"1 Avg Coverage 65.5% 55.3% <85% OK\\n\",\n \"2 Coverage Std 0.183 0.251 >0.065 OK\\n\",\n \"3 Max Overlap 87.3% 57.4% <80% OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[OK] formula_1: All quality checks passed\\n\",\n \"\\n\",\n \"======================================================================\\n\",\n \"[DECISION] Satisfied? Run Cell 6.5 to apply. Otherwise edit Cell 6.2 and re-run 6.3.\\n\",\n \"[TIP] Use Cell 6.4.1 to select specific roles from OLD/NEW\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.4 Preview Regenerated Roles (Compare OLD vs NEW + Quality Check)\\n\",\n \"# Supports multiple databases\\n\",\n \"import numpy as np\\n\",\n \"from src.role_evaluator.quality_metrics import RoleQualityEvaluator\\n\",\n \"\\n\",\n \"pd.set_option('display.max_colwidth', None)\\n\",\n \"pd.set_option('display.max_rows', None)\\n\",\n \"pd.set_option('display.width', None)\\n\",\n \"\\n\",\n \"if 'regenerated_results' in dir() and regenerated_results:\\n\",\n \" for db_name, regen_result in regenerated_results.items():\\n\",\n \" if regen_result[\\\"status\\\"] != \\\"success\\\":\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"[SKIP] {db_name}: {regen_result.get('error', 'failed')}\\\")\\n\",\n \" continue\\n\",\n \" \\n\",\n \" regenerated_assignments = regen_result[\\\"assignments\\\"]\\n\",\n \" target_schema = target_schemas.get(db_name)\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"Database: {db_name}\\\")\\n\",\n \" print(f\\\"{'='*70}\\\")\\n\",\n \" \\n\",\n \" # --- NEW Role Summary ---\\n\",\n \" new_summary = []\\n\",\n \" for r in regenerated_assignments:\\n\",\n \" policy = r.get('policy', {})\\n\",\n \" total_cols = count_policy_columns(policy, target_schema)\\n\",\n \" has_wc = has_wildcard_policy(policy)\\n\",\n \" cols_display = f\\\"{total_cols}\\\" + (\\\" (*)\\\" if has_wc else \\\"\\\")\\n\",\n \" policy_str = \\\"; \\\".join([\\n\",\n \" f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" \\n\",\n \" for t, c in policy.items()\\n\",\n \" ])\\n\",\n \" new_summary.append({\\n\",\n \" \\\"Role\\\": r['role'],\\n\",\n \" \\\"Description\\\": r.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Cols\\\": cols_display,\\n\",\n \" \\\"Policy\\\": policy_str\\n\",\n \" })\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n=== NEW Roles ({len(regenerated_assignments)}) ===\\\")\\n\",\n \" display(pd.DataFrame(new_summary))\\n\",\n \" \\n\",\n \" # --- Quality Metrics ---\\n\",\n \" if target_schema:\\n\",\n \" total_schema_cols = sum(len(t['columns']) for t in target_schema.values())\\n\",\n \" else:\\n\",\n \" total_schema_cols = 10\\n\",\n \" \\n\",\n \" # NEW metrics\\n\",\n \" new_coverages = [count_policy_columns(r.get('policy', {}), target_schema) / total_schema_cols \\n\",\n \" for r in regenerated_assignments]\\n\",\n \" new_avg_cov = np.mean(new_coverages)\\n\",\n \" new_cov_std = np.std(new_coverages)\\n\",\n \" \\n\",\n \" new_max_overlap = 0.0\\n\",\n \" non_admin_new = [r for r in regenerated_assignments if 'admin' not in r['role'].lower()]\\n\",\n \" for i, r1 in enumerate(non_admin_new):\\n\",\n \" set1 = RoleQualityEvaluator.policy_to_column_set(r1.get('policy', {}))\\n\",\n \" for r2 in non_admin_new[i+1:]:\\n\",\n \" set2 = RoleQualityEvaluator.policy_to_column_set(r2.get('policy', {}))\\n\",\n \" new_max_overlap = max(new_max_overlap, RoleQualityEvaluator.jaccard_similarity(set1, set2))\\n\",\n \" \\n\",\n \" # OLD metrics\\n\",\n \" old_roles = all_assignments.get('assignments', {}).get(db_name, [])\\n\",\n \" if old_roles:\\n\",\n \" old_coverages = [count_policy_columns(r.get('policy', {}), target_schema) / total_schema_cols \\n\",\n \" for r in old_roles]\\n\",\n \" old_avg_cov = np.mean(old_coverages)\\n\",\n \" old_cov_std = np.std(old_coverages)\\n\",\n \" \\n\",\n \" old_max_overlap = 0.0\\n\",\n \" non_admin_old = [r for r in old_roles if 'admin' not in r['role'].lower()]\\n\",\n \" for i, r1 in enumerate(non_admin_old):\\n\",\n \" set1 = RoleQualityEvaluator.policy_to_column_set(r1.get('policy', {}))\\n\",\n \" for r2 in non_admin_old[i+1:]:\\n\",\n \" set2 = RoleQualityEvaluator.policy_to_column_set(r2.get('policy', {}))\\n\",\n \" old_max_overlap = max(old_max_overlap, RoleQualityEvaluator.jaccard_similarity(set1, set2))\\n\",\n \" else:\\n\",\n \" old_avg_cov, old_cov_std, old_max_overlap = 0, 0, 0\\n\",\n \" \\n\",\n \" # Comparison table (using QUALITY_THRESHOLDS from Cell 5.1)\\n\",\n \" def status(metric, val):\\n\",\n \" if metric == \\\"Coverage\\\": \\n\",\n \" return \\\"WARN\\\" if val > QUALITY_THRESHOLDS.get(\\\"coverage_max\\\", 0.90) else \\\"OK\\\"\\n\",\n \" if metric == \\\"CovStd\\\": \\n\",\n \" return \\\"WARN\\\" if val < QUALITY_THRESHOLDS.get(\\\"coverage_std_min\\\", 0.08) else \\\"OK\\\"\\n\",\n \" if metric == \\\"MaxOverlap\\\": \\n\",\n \" return \\\"WARN\\\" if val > QUALITY_THRESHOLDS.get(\\\"max_overlap\\\", 0.80) else \\\"OK\\\"\\n\",\n \" return \\\"OK\\\"\\n\",\n \" \\n\",\n \" quality_df = pd.DataFrame([\\n\",\n \" {\\\"Metric\\\": \\\"Roles\\\", \\\"OLD\\\": len(old_roles), \\\"NEW\\\": len(regenerated_assignments)},\\n\",\n \" {\\\"Metric\\\": \\\"Avg Coverage\\\", \\\"OLD\\\": f\\\"{old_avg_cov:.1%}\\\", \\\"NEW\\\": f\\\"{new_avg_cov:.1%}\\\", \\n\",\n \" \\\"Threshold\\\": f\\\"<{QUALITY_THRESHOLDS.get('coverage_max', 0.90):.0%}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"Coverage\\\", new_avg_cov)},\\n\",\n \" {\\\"Metric\\\": \\\"Coverage Std\\\", \\\"OLD\\\": f\\\"{old_cov_std:.3f}\\\", \\\"NEW\\\": f\\\"{new_cov_std:.3f}\\\",\\n\",\n \" \\\"Threshold\\\": f\\\">{QUALITY_THRESHOLDS.get('coverage_std_min', 0.08)}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"CovStd\\\", new_cov_std)},\\n\",\n \" {\\\"Metric\\\": \\\"Max Overlap\\\", \\\"OLD\\\": f\\\"{old_max_overlap:.1%}\\\", \\\"NEW\\\": f\\\"{new_max_overlap:.1%}\\\",\\n\",\n \" \\\"Threshold\\\": f\\\"<{QUALITY_THRESHOLDS.get('max_overlap', 0.80):.0%}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"MaxOverlap\\\", new_max_overlap)},\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Quality Comparison ===\\\")\\n\",\n \" display(quality_df)\\n\",\n \" \\n\",\n \" warn_count = quality_df['Status'].eq('WARN').sum() if 'Status' in quality_df.columns else 0\\n\",\n \" if warn_count == 0:\\n\",\n \" print(f\\\"[OK] {db_name}: All quality checks passed\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\"[WARN] {db_name}: {warn_count} issue(s)\\\")\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(\\\"[DECISION] Satisfied? Run Cell 6.5 to apply. Otherwise edit Cell 6.2 and re-run 6.3.\\\")\\n\",\n \" print(\\\"[TIP] Use Cell 6.4.1 to select specific roles from OLD/NEW\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[WARN] No regenerated results. Run Cell 6.3 first.\\\")\\n\",\n \"\\n\",\n \"pd.reset_option('display.max_colwidth')\\n\",\n \"pd.reset_option('display.max_rows')\\n\",\n \"pd.reset_option('display.width')\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 70,\n \"id\": \"f003a014\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Role Selection Summary ===\\n\",\n \"\\n\",\n \"============================================================\\n\",\n \"Database: formula_1\\n\",\n \" From OLD (0): (none)\\n\",\n \" From NEW (4): ['SystemManager', 'RaceAnalyst', 'PublicRelations', 'DriverManager']\\n\",\n \" Combined: 4 roles\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
SourceRoleDescriptionTablesPolicy
0NEWSystemManagerFull administrative access for system maintena...13circuits: [*]; constructors: [*]; drivers: [*]...
1NEWRaceAnalystAnalyzes race performance data including lap t...8circuits: [circuitId, name, location, country,...
2NEWPublicRelationsAccesses public information about circuits, dr...6circuits: [circuitId, name, location, country,...
3NEWDriverManagerManages driver information and personal detail...4drivers: [driverId, driverRef, number, code, f...
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Source Role Description \\\\\\n\",\n \"0 NEW SystemManager Full administrative access for system maintena... \\n\",\n \"1 NEW RaceAnalyst Analyzes race performance data including lap t... \\n\",\n \"2 NEW PublicRelations Accesses public information about circuits, dr... \\n\",\n \"3 NEW DriverManager Manages driver information and personal detail... \\n\",\n \"\\n\",\n \" Tables Policy \\n\",\n \"0 13 circuits: [*]; constructors: [*]; drivers: [*]... \\n\",\n \"1 8 circuits: [circuitId, name, location, country,... \\n\",\n \"2 6 circuits: [circuitId, name, location, country,... \\n\",\n \"3 4 drivers: [driverId, driverRef, number, code, f... \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"============================================================\\n\",\n \"[NEXT] Run Cell 6.5 to apply combined role sets\\n\",\n \"[TIP] Edit ROLE_SELECTION above to customize, then re-run this cell\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.4.1 Select & Combine Roles from OLD and NEW\\n\",\n \"# Human expert picks best roles from both versions to create final role set\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EDIT HERE: Specify which roles to keep from each version\\n\",\n \"# Format: {\\\"db_name\\\": {\\\"old\\\": [role_names], \\\"new\\\": [role_names]}}\\n\",\n \"# Leave empty [] to skip a version, or use [\\\"*\\\"] to keep all from that version\\n\",\n \"# ============================================================\\n\",\n \"ROLE_SELECTION = {\\n\",\n \" \\\"formula_1\\\": {\\n\",\n \" \\\"old\\\": [], # e.g., [\\\"DataAnalyst\\\", \\\"Researcher\\\"]\\n\",\n \" \\\"new\\\": [\\\"SystemManager\\\", \\\"RaceAnalyst\\\", \\\"PublicRelations\\\", \\\"DriverManager\\\"], # keep all new roles\\n\",\n \" },\\n\",\n \" # \\\"financial\\\": {\\n\",\n \" # \\\"old\\\": [],\\n\",\n \" # \\\"new\\\": [\\\"*\\\"],\\n\",\n \" # },\\n\",\n \"}\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# Process selections and create combined role sets\\n\",\n \"# ============================================================\\n\",\n \"combined_results = {}\\n\",\n \"\\n\",\n \"if 'regenerated_results' in dir() and regenerated_results:\\n\",\n \" print(\\\"=== Role Selection Summary ===\\\\n\\\")\\n\",\n \" \\n\",\n \" for db_name in valid_target_dbs:\\n\",\n \" selection = ROLE_SELECTION.get(db_name, {\\\"old\\\": [], \\\"new\\\": [\\\"*\\\"]})\\n\",\n \" old_keep = selection.get(\\\"old\\\", [])\\n\",\n \" new_keep = selection.get(\\\"new\\\", [\\\"*\\\"])\\n\",\n \" \\n\",\n \" # Get OLD roles\\n\",\n \" old_roles = all_assignments.get('assignments', {}).get(db_name, [])\\n\",\n \" old_role_dict = {r['role']: r for r in old_roles}\\n\",\n \" \\n\",\n \" # Get NEW roles\\n\",\n \" regen_result = regenerated_results.get(db_name, {})\\n\",\n \" if regen_result.get(\\\"status\\\") != \\\"success\\\":\\n\",\n \" print(f\\\"[SKIP] {db_name}: regeneration failed\\\")\\n\",\n \" continue\\n\",\n \" new_roles = regen_result[\\\"assignments\\\"]\\n\",\n \" new_role_dict = {r['role']: r for r in new_roles}\\n\",\n \" \\n\",\n \" # Build combined role set\\n\",\n \" combined_roles = []\\n\",\n \" selected_from_old = []\\n\",\n \" selected_from_new = []\\n\",\n \" \\n\",\n \" # Select from OLD\\n\",\n \" if old_keep == [\\\"*\\\"]:\\n\",\n \" combined_roles.extend(old_roles)\\n\",\n \" selected_from_old = [r['role'] for r in old_roles]\\n\",\n \" else:\\n\",\n \" for role_name in old_keep:\\n\",\n \" if role_name in old_role_dict:\\n\",\n \" combined_roles.append(old_role_dict[role_name])\\n\",\n \" selected_from_old.append(role_name)\\n\",\n \" else:\\n\",\n \" print(f\\\" [WARN] {db_name}: OLD role '{role_name}' not found\\\")\\n\",\n \" \\n\",\n \" # Select from NEW\\n\",\n \" if new_keep == [\\\"*\\\"]:\\n\",\n \" combined_roles.extend(new_roles)\\n\",\n \" selected_from_new = [r['role'] for r in new_roles]\\n\",\n \" else:\\n\",\n \" for role_name in new_keep:\\n\",\n \" if role_name in new_role_dict:\\n\",\n \" combined_roles.append(new_role_dict[role_name])\\n\",\n \" selected_from_new.append(role_name)\\n\",\n \" else:\\n\",\n \" print(f\\\" [WARN] {db_name}: NEW role '{role_name}' not found\\\")\\n\",\n \" \\n\",\n \" combined_results[db_name] = combined_roles\\n\",\n \" \\n\",\n \" # Display summary\\n\",\n \" print(f\\\"{'='*60}\\\")\\n\",\n \" print(f\\\"Database: {db_name}\\\")\\n\",\n \" print(f\\\" From OLD ({len(selected_from_old)}): {selected_from_old if selected_from_old else '(none)'}\\\")\\n\",\n \" print(f\\\" From NEW ({len(selected_from_new)}): {selected_from_new if selected_from_new else '(none)'}\\\")\\n\",\n \" print(f\\\" Combined: {len(combined_roles)} roles\\\")\\n\",\n \" \\n\",\n \" # Show combined roles table\\n\",\n \" target_schema = target_schemas.get(db_name)\\n\",\n \" combined_summary = []\\n\",\n \" for r in combined_roles:\\n\",\n \" policy = r.get('policy', {})\\n\",\n \" source = \\\"OLD\\\" if r['role'] in old_role_dict and r['role'] not in [nr['role'] for nr in new_roles] else \\\"NEW\\\"\\n\",\n \" if r['role'] in old_role_dict and r['role'] in [nr['role'] for nr in new_roles]:\\n\",\n \" source = \\\"NEW\\\" # Prefer NEW if same name exists in both\\n\",\n \" combined_summary.append({\\n\",\n \" \\\"Source\\\": source,\\n\",\n \" \\\"Role\\\": r['role'],\\n\",\n \" \\\"Description\\\": r.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Policy\\\": \\\"; \\\".join([f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" for t, c in policy.items()])\\n\",\n \" })\\n\",\n \" \\n\",\n \" display(pd.DataFrame(combined_summary))\\n\",\n \" print()\\n\",\n \" \\n\",\n \" print(\\\"=\\\"*60)\\n\",\n \" print(f\\\"[NEXT] Run Cell 6.5 to apply combined role sets\\\")\\n\",\n \" print(\\\"[TIP] Edit ROLE_SELECTION above to customize, then re-run this cell\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[WARN] No regenerated results. Run Cell 6.3 first.\\\")\\n\",\n \" print(\\\"\\\\n[HINT] Available roles to select from:\\\")\\n\",\n \" print(\\\" OLD: roles from current assignments\\\")\\n\",\n \" print(\\\" NEW: roles from regeneration\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 71,\n \"id\": \"6cb24c7d\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[MODE] Applying COMBINED role sets (from Cell 6.4.1 selection)\\n\",\n \"\\n\",\n \"=== Changes Applied ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseOld RolesNew RolesSource
0formula_154Combined (OLD+NEW)
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Old Roles New Roles Source\\n\",\n \"0 formula_1 5 4 Combined (OLD+NEW)\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"Saved to: bird_column_level_rbac_assignments_v2_20251230.json\\n\",\n \"\\n\",\n \"[OK] State cleared. Select new database(s) to continue.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.5 Apply Changes (Save Combined Role Sets)\\n\",\n \"# Uses combined_results from Cell 6.4.1 (selected from OLD + NEW)\\n\",\n \"from datetime import datetime\\n\",\n \"\\n\",\n \"APPLY_CHANGES = True # Set to True to confirm\\n\",\n \"\\n\",\n \"if APPLY_CHANGES:\\n\",\n \" # Prefer combined_results (from selection), fallback to regenerated_results\\n\",\n \" use_combined = 'combined_results' in dir() and combined_results\\n\",\n \" use_regenerated = 'regenerated_results' in dir() and regenerated_results\\n\",\n \" \\n\",\n \" if use_combined:\\n\",\n \" print(\\\"[MODE] Applying COMBINED role sets (from Cell 6.4.1 selection)\\\\n\\\")\\n\",\n \" applied = []\\n\",\n \" \\n\",\n \" for db_name, combined_roles in combined_results.items():\\n\",\n \" if not combined_roles:\\n\",\n \" continue\\n\",\n \" \\n\",\n \" old_count = len(all_assignments.get('assignments', {}).get(db_name, []))\\n\",\n \" all_assignments['assignments'][db_name] = combined_roles\\n\",\n \" applied.append({\\n\",\n \" \\\"Database\\\": db_name,\\n\",\n \" \\\"Old Roles\\\": old_count,\\n\",\n \" \\\"New Roles\\\": len(combined_roles),\\n\",\n \" \\\"Source\\\": \\\"Combined (OLD+NEW)\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" if applied:\\n\",\n \" OUTPUT_DIR = project_root / 'outputs'\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = OUTPUT_DIR / f'bird_column_level_rbac_assignments_v2_{today}.json'\\n\",\n \" with open(output_path, 'w') as f:\\n\",\n \" json.dump(all_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \" \\n\",\n \" print(\\\"=== Changes Applied ===\\\")\\n\",\n \" display(pd.DataFrame(applied))\\n\",\n \" print(f\\\"\\\\nSaved to: {output_path.name}\\\")\\n\",\n \" \\n\",\n \" # Clear state\\n\",\n \" combined_results = {}\\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"\\\\n[OK] State cleared. Select new database(s) to continue.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No combined role sets to apply. Run Cell 6.4.1 first.\\\")\\n\",\n \" \\n\",\n \" elif use_regenerated:\\n\",\n \" print(\\\"[MODE] Applying ALL NEW roles (no selection made)\\\\n\\\")\\n\",\n \" applied = []\\n\",\n \" \\n\",\n \" for db_name, regen_result in regenerated_results.items():\\n\",\n \" if regen_result[\\\"status\\\"] != \\\"success\\\":\\n\",\n \" continue\\n\",\n \" \\n\",\n \" old_count = len(all_assignments.get('assignments', {}).get(db_name, []))\\n\",\n \" all_assignments['assignments'][db_name] = regen_result[\\\"assignments\\\"]\\n\",\n \" applied.append({\\n\",\n \" \\\"Database\\\": db_name,\\n\",\n \" \\\"Old Roles\\\": old_count,\\n\",\n \" \\\"New Roles\\\": len(regen_result[\\\"assignments\\\"]),\\n\",\n \" \\\"Source\\\": \\\"All NEW\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" if applied:\\n\",\n \" OUTPUT_DIR = project_root / 'outputs'\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = OUTPUT_DIR / f'bird_column_level_rbac_assignments_v2_{today}.json'\\n\",\n \" with open(output_path, 'w') as f:\\n\",\n \" json.dump(all_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \" \\n\",\n \" print(\\\"=== Changes Applied ===\\\")\\n\",\n \" display(pd.DataFrame(applied))\\n\",\n \" print(f\\\"\\\\nSaved to: {output_path.name}\\\")\\n\",\n \" \\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"\\\\n[OK] State cleared. Select new database(s) to continue.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No successful regenerations to apply.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No results to apply. Run Cell 6.3 and optionally Cell 6.4.1 first.\\\")\\n\",\n \"else:\\n\",\n \" has_combined = 'combined_results' in dir() and combined_results\\n\",\n \" has_regenerated = 'regenerated_results' in dir() and regenerated_results\\n\",\n \" \\n\",\n \" if has_combined:\\n\",\n \" print(f\\\"[INFO] {len(combined_results)} database(s) with COMBINED role sets ready\\\")\\n\",\n \" print(\\\"[TIP] These are your custom selections from OLD + NEW\\\")\\n\",\n \" elif has_regenerated:\\n\",\n \" success_count = sum(1 for r in regenerated_results.values() if r[\\\"status\\\"] == \\\"success\\\")\\n\",\n \" print(f\\\"[INFO] {success_count} database(s) with ALL NEW roles ready\\\")\\n\",\n \" print(\\\"[TIP] Run Cell 6.4.1 to select specific roles from OLD/NEW\\\")\\n\",\n \" \\n\",\n \" print(\\\"\\\\n[INFO] APPLY_CHANGES is False. Set to True and re-run to apply.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"f1bd0bc2\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# 6.6 Regenerate RBAC Dataset with Updated Role Assignments\\n\",\n \"# Run this after Cell 6.5 to create the final dataset\\n\",\n \"\\n\",\n \"from datetime import datetime\\n\",\n \"import importlib\\n\",\n \"\\n\",\n \"# IMPORTANT: Reload ALL dependent modules to pick up CTE parsing fix\\n\",\n \"import src.processors.column_extractor\\n\",\n \"import src.processors.column_permission_checker\\n\",\n \"import src.processors.column_level_rbac_generator\\n\",\n \"\\n\",\n \"importlib.reload(src.processors.column_extractor)\\n\",\n \"importlib.reload(src.processors.column_permission_checker)\\n\",\n \"importlib.reload(src.processors.column_level_rbac_generator)\\n\",\n \"\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator\\n\",\n \"\\n\",\n \"# Find the updated role assignments file (v2 if exists, otherwise latest)\\n\",\n \"v2_files = sorted(glob.glob(str(project_root / 'outputs' / 'bird_column_level_rbac_assignments_v2_*.json')))\\n\",\n \"if v2_files:\\n\",\n \" UPDATED_ROLE_PATH = v2_files[-1]\\n\",\n \"else:\\n\",\n \" role_files = sorted(glob.glob(str(project_root / 'outputs' / 'column_level_role_assignments_bird_*.json')))\\n\",\n \" UPDATED_ROLE_PATH = role_files[-1] if role_files else None\\n\",\n \"\\n\",\n \"if UPDATED_ROLE_PATH:\\n\",\n \" print(f\\\"=== Regenerating RBAC Dataset ===\\\")\\n\",\n \" print(f\\\"Role assignments: {Path(UPDATED_ROLE_PATH).name}\\\")\\n\",\n \" print(f\\\"BIRD data: {BIRD_DATA_PATH}\\\")\\n\",\n \" \\n\",\n \" # Initialize generator with updated roles\\n\",\n \" generator = ColumnLevelRBACGenerator(\\n\",\n \" role_assignments_path=UPDATED_ROLE_PATH,\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH),\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" project_root=str(project_root),\\n\",\n \" seed=42\\n\",\n \" )\\n\",\n \" \\n\",\n \" # Generate dataset\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = project_root / 'outputs' / f'column_level_rbac_dataset_bird_{today}.json'\\n\",\n \" \\n\",\n \" full_stats = generator.generate_and_save(\\n\",\n \" output_path=str(output_path),\\n\",\n \" roles_per_db=None,\\n\",\n \" queries_per_role=None\\n\",\n \" )\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n✓ Dataset saved to: {output_path.name}\\\")\\n\",\n \" print(f\\\"\\\\n=== Dataset Statistics ===\\\")\\n\",\n \" for k, v in full_stats.items():\\n\",\n \" if k == 'by_database':\\n\",\n \" print(f\\\"\\\\nPer-database distribution:\\\")\\n\",\n \" for db_id, counts in sorted(v.items()):\\n\",\n \" print(f\\\" {db_id}: allowed={counts['allowed']}, denied={counts['denied']}\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[ERROR] No role assignments file found. Run Cell 6.5 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"a9345c97\",\n \"metadata\": {},\n \"source\": [\n \"## 7. Summary\\n\",\n \"\\n\",\n \"### Generated Files\\n\",\n \"- `outputs/column_level_role_assignments_bird_YYYYMMDD.json` - Role assignments with column-level policies\\n\",\n \"- `outputs/bird_column_level_rbac_assignments_v2_YYYYMMDD.json` - Updated role assignments after regeneration\\n\",\n \"- `outputs/column_level_rbac_dataset_bird_YYYYMMDD.json` - Column-Level RBAC dataset\\n\",\n \"\\n\",\n \"### Workflow\\n\",\n \"\\n\",\n \"| Section | Description |\\n\",\n \"|---------|-------------|\\n\",\n \"| **3** | Batch process all BIRD databases to generate initial roles |\\n\",\n \"| **4** | Generate RBAC dataset from role assignments |\\n\",\n \"| **5** | Quality assessment with configurable thresholds |\\n\",\n \"| **6.1** | Select problematic database(s) and view current state |\\n\",\n \"| **6.2** | Write regeneration hints with problem description |\\n\",\n \"| **6.3** | Execute LLM regeneration with hints |\\n\",\n \"| **6.4** | Preview OLD vs NEW roles with quality comparison |\\n\",\n \"| **6.4.1** | Select & combine best roles from OLD and NEW |\\n\",\n \"| **6.5** | Apply changes (save updated role assignments) |\\n\",\n \"| **6.6** | Regenerate RBAC dataset with updated roles |\\n\",\n \"\\n\",\n \"### Quality Assessment Module (Section 5)\\n\",\n \"\\n\",\n \"```python\\n\",\n \"from src.role_evaluator import RoleQualityEvaluator, RoleQualityVisualizer\\n\",\n \"\\n\",\n \"evaluator = RoleQualityEvaluator(\\n\",\n \" role_assignments_path=\\\"outputs/column_level_role_assignments_bird.json\\\",\\n\",\n \" dataset_path=\\\"outputs/column_level_rbac_dataset_bird.json\\\",\\n\",\n \" schema_dir=\\\"data/Bird/dev_20251106/dev_databases\\\",\\n\",\n \" embed_model=\\\"BAAI/bge-small-en-v1.5\\\" # or \\\"text-embedding-3-small\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"report = evaluator.evaluate_all()\\n\",\n \"visualizer = RoleQualityVisualizer(evaluator=evaluator, report=report)\\n\",\n \"visualizer.plot_quality_dashboard()\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Quality Thresholds (Configurable)\\n\",\n \"\\n\",\n \"| Metric | Default | Description |\\n\",\n \"|--------|---------|-------------|\\n\",\n \"| `deny_rate_min` | 5% | Warn if deny rate below (roles too permissive) |\\n\",\n \"| `coverage_max` | 90% | Warn if avg coverage above (roles too broad) |\\n\",\n \"| `coverage_std_min` | 0.08 | Warn if coverage std below (low diversity) |\\n\",\n \"| `max_overlap` | 80% | Warn if max overlap above (redundant roles) |\\n\",\n \"\\n\",\n \"### External Modules\\n\",\n \"\\n\",\n \"1. **`src/role_evaluator/quality_metrics.py`** - Quality metrics computation\\n\",\n \" - `RoleQualityEvaluator`: Comprehensive evaluator\\n\",\n \" - `DenyRateMetrics`, `SemanticMetrics`, `OverlapMetrics`: Data classes\\n\",\n \" - `print_quality_report()`: Formatted report output\\n\",\n \"\\n\",\n \"2. **`src/role_evaluator/quality_visualizer.py`** - Visualization suite\\n\",\n \" - `plot_deny_rate_distribution()`: Permission distribution chart\\n\",\n \" - `plot_semantic_alignment()`: Semantic alignment scatter plot\\n\",\n \" - `plot_policy_overlap_bars()`: Policy overlap bar chart\\n\",\n \" - `plot_quality_dashboard()`: Comprehensive dashboard\\n\",\n \"\\n\",\n \"3. **`src/processors/column_level_rbac_generator.py`** - Dataset generation\\n\",\n \" - `ColumnLevelRBACGenerator`: Generate RBAC dataset from role assignments\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \"llm4db\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.10.18\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"}, "371a5f4857980ef1c5e9e5714af4d820697cca97": {"t": 1785753620.205377, "n": 427471, "h": "e6b8a7a78d24465c", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"id\": \"c4bddd25\",\n \"metadata\": {},\n \"source\": [\n \"## 0. Import and Setup\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"id\": \"93292a4c\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Project root: /home/feiy/Role-SQL-benchmark\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Setup and imports\\n\",\n \"import sys\\n\",\n \"import json\\n\",\n \"import sqlite3\\n\",\n \"from pathlib import Path\\n\",\n \"from pprint import pprint\\n\",\n \"\\n\",\n \"# Add project root to path\\n\",\n \"project_root = Path.cwd().parent\\n\",\n \"sys.path.insert(0, str(project_root))\\n\",\n \"\\n\",\n \"print(f\\\"Project root: {project_root}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 2,\n \"id\": \"bce399e4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Available API keys:\\n\",\n \" OPENAI_API_KEY: ✓\\n\",\n \" DEEPSEEK_API_KEY: ✓\\n\",\n \" DEEPINFRA_API_KEY: ✓\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Load environment and initialize Oracle\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"import os\\n\",\n \"\\n\",\n \"load_dotenv(project_root / '.env')\\n\",\n \"\\n\",\n \"# Check available API keys\\n\",\n \"api_keys = {\\n\",\n \" 'OPENAI_API_KEY': bool(os.getenv('OPENAI_API_KEY')),\\n\",\n \" 'DEEPSEEK_API_KEY': bool(os.getenv('DEEPSEEK_API_KEY')),\\n\",\n \" 'DEEPINFRA_API_KEY': bool(os.getenv('DEEPINFRA_API_KEY')),\\n\",\n \"}\\n\",\n \"print(\\\"Available API keys:\\\")\\n\",\n \"for k, v in api_keys.items():\\n\",\n \" print(f\\\" {k}: {'✓' if v else '✗'}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 3,\n \"id\": \"a4d69b7c\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Using model: deepseek-chat\\n\"\n ]\n },\n {\n \"name\": \"stderr\",\n \"output_type\": \"stream\",\n \"text\": [\n \"/home/feiy/anaconda3/envs/llm4db/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\\n\",\n \" from .autonotebook import tqdm as notebook_tqdm\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Initialize LLM Oracle\\n\",\n \"from src.llm_oracle import Oracle\\n\",\n \"\\n\",\n \"# Choose model based on available keys (prefer DeepSeek for cost efficiency)\\n\",\n \"if os.getenv('DEEPSEEK_API_KEY'):\\n\",\n \" MODEL = \\\"deepseek-chat\\\"\\n\",\n \" API_KEY = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"elif os.getenv('OPENAI_API_KEY'):\\n\",\n \" MODEL = \\\"gpt-4o-mini\\\"\\n\",\n \" API_KEY = os.getenv('OPENAI_API_KEY')\\n\",\n \"else:\\n\",\n \" raise ValueError(\\\"No API key available!\\\")\\n\",\n \"\\n\",\n \"oracle = Oracle(model=MODEL, apikey=API_KEY)\\n\",\n \"print(f\\\"Using model: {MODEL}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8809cf55\",\n \"metadata\": {},\n \"source\": [\n \"## 1. Load Sample Database Schema\\n\",\n \"\\n\",\n \"We'll use a BIRD database with interesting column structure for testing.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 4,\n \"id\": \"e9dcc61c\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Import shared policy utility functions\\n\",\n \"from src.role_evaluator.quality_metrics import RoleQualityEvaluator\\n\",\n \"\\n\",\n \"# Convenience aliases for the static methods\\n\",\n \"count_policy_columns = RoleQualityEvaluator.count_policy_columns\\n\",\n \"has_wildcard_policy = RoleQualityEvaluator.has_wildcard_policy\\n\",\n \"\\n\",\n \"def get_schema_from_sqlite(db_path: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Extract detailed schema from SQLite database.\\\"\\\"\\\"\\n\",\n \" conn = sqlite3.connect(db_path)\\n\",\n \" cursor = conn.cursor()\\n\",\n \" \\n\",\n \" # Get all tables\\n\",\n \" cursor.execute(\\\"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'\\\")\\n\",\n \" tables = [row[0] for row in cursor.fetchall()]\\n\",\n \" \\n\",\n \" schema = {}\\n\",\n \" for table in tables:\\n\",\n \" cursor.execute(f\\\"PRAGMA table_info(`{table}`)\\\")\\n\",\n \" columns = cursor.fetchall()\\n\",\n \" \\n\",\n \" cursor.execute(f\\\"PRAGMA foreign_key_list(`{table}`)\\\")\\n\",\n \" fks = {row[3]: f\\\"{row[2]}.{row[4]}\\\" for row in cursor.fetchall()}\\n\",\n \" \\n\",\n \" schema[table] = {\\n\",\n \" 'columns': [\\n\",\n \" {\\n\",\n \" 'name': col[1],\\n\",\n \" 'type': col[2] or 'TEXT',\\n\",\n \" 'pk': col[5] == 1,\\n\",\n \" 'not_null': col[3] == 1,\\n\",\n \" 'fk': fks.get(col[1])\\n\",\n \" }\\n\",\n \" for col in columns\\n\",\n \" ]\\n\",\n \" }\\n\",\n \" \\n\",\n \" conn.close()\\n\",\n \" return schema\\n\",\n \"\\n\",\n \"def format_schema_for_prompt(schema: dict, db_name: str) -> str:\\n\",\n \" \\\"\\\"\\\"Format schema as text for LLM prompt.\\\"\\\"\\\"\\n\",\n \" lines = [f\\\"Database: {db_name}\\\\n\\\"]\\n\",\n \" \\n\",\n \" for table, info in schema.items():\\n\",\n \" lines.append(f\\\"Table: {table}\\\")\\n\",\n \" lines.append(\\\"Columns:\\\")\\n\",\n \" for col in info['columns']:\\n\",\n \" constraints = []\\n\",\n \" if col['pk']:\\n\",\n \" constraints.append(\\\"PRIMARY KEY\\\")\\n\",\n \" if col['not_null'] and not col['pk']:\\n\",\n \" constraints.append(\\\"NOT NULL\\\")\\n\",\n \" if col['fk']:\\n\",\n \" constraints.append(f\\\"FK -> {col['fk']}\\\")\\n\",\n \" \\n\",\n \" constraint_str = f\\\" [{', '.join(constraints)}]\\\" if constraints else \\\"\\\"\\n\",\n \" lines.append(f\\\" - {col['name']} ({col['type']}){constraint_str}\\\")\\n\",\n \" lines.append(\\\"\\\")\\n\",\n \" \\n\",\n \" return \\\"\\\\n\\\".join(lines)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 5,\n \"id\": \"705d64b1\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Available BIRD databases (11):\\n\",\n \" - california_schools\\n\",\n \" - card_games\\n\",\n \" - codebase_community\\n\",\n \" - debit_card_specializing\\n\",\n \" - european_football_2\\n\",\n \" - financial\\n\",\n \" - formula_1\\n\",\n \" - student_club\\n\",\n \" - superhero\\n\",\n \" - thrombosis_prediction\\n\",\n \" ...\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Load a sample BIRD database - use the latest 2025 version\\n\",\n \"bird_db_dir = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases'\\n\",\n \"\\n\",\n \"# List available databases\\n\",\n \"available_dbs = [d.name for d in bird_db_dir.iterdir() if d.is_dir()]\\n\",\n \"print(f\\\"Available BIRD databases ({len(available_dbs)}):\\\")\\n\",\n \"for db in sorted(available_dbs)[:10]:\\n\",\n \" print(f\\\" - {db}\\\")\\n\",\n \"print(\\\" ...\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 6,\n \"id\": \"f9e1a86a\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Loading schema from: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev_databases/california_schools/california_schools.sqlite\\n\",\n \"\\n\",\n \"Tables: ['frpm', 'satscores', 'schools']\\n\",\n \"\\n\",\n \"frpm: 29 columns\\n\",\n \" - CDSCode (TEXT)\\n\",\n \" - Academic Year (TEXT)\\n\",\n \" - County Code (TEXT)\\n\",\n \" - District Code (INTEGER)\\n\",\n \" - School Code (TEXT)\\n\",\n \" ... and 24 more\\n\",\n \"\\n\",\n \"satscores: 11 columns\\n\",\n \" - cds (TEXT)\\n\",\n \" - rtype (TEXT)\\n\",\n \" - sname (TEXT)\\n\",\n \" - dname (TEXT)\\n\",\n \" - cname (TEXT)\\n\",\n \" ... and 6 more\\n\",\n \"\\n\",\n \"schools: 49 columns\\n\",\n \" - CDSCode (TEXT)\\n\",\n \" - NCESDist (TEXT)\\n\",\n \" - NCESSchool (TEXT)\\n\",\n \" - StatusType (TEXT)\\n\",\n \" - County (TEXT)\\n\",\n \" ... and 44 more\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Select a database with moderate complexity\\n\",\n \"# 'california_schools' has tables with sensitive-looking columns\\n\",\n \"TEST_DB = \\\"california_schools\\\"\\n\",\n \"db_path = bird_db_dir / TEST_DB / f\\\"{TEST_DB}.sqlite\\\"\\n\",\n \"\\n\",\n \"print(f\\\"Loading schema from: {db_path}\\\")\\n\",\n \"schema = get_schema_from_sqlite(str(db_path))\\n\",\n \"\\n\",\n \"print(f\\\"\\\\nTables: {list(schema.keys())}\\\")\\n\",\n \"for table, info in schema.items():\\n\",\n \" print(f\\\"\\\\n{table}: {len(info['columns'])} columns\\\")\\n\",\n \" for col in info['columns'][:5]:\\n\",\n \" print(f\\\" - {col['name']} ({col['type']})\\\")\\n\",\n \" if len(info['columns']) > 5:\\n\",\n \" print(f\\\" ... and {len(info['columns']) - 5} more\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 7,\n \"id\": \"e5fb0114\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Database: california_schools\\n\",\n \"\\n\",\n \"Table: frpm\\n\",\n \"Columns:\\n\",\n \" - CDSCode (TEXT) [PRIMARY KEY, FK -> schools.CDSCode]\\n\",\n \" - Academic Year (TEXT)\\n\",\n \" - County Code (TEXT)\\n\",\n \" - District Code (INTEGER)\\n\",\n \" - School Code (TEXT)\\n\",\n \" - County Name (TEXT)\\n\",\n \" - District Name (TEXT)\\n\",\n \" - School Name (TEXT)\\n\",\n \" - District Type (TEXT)\\n\",\n \" - School Type (TEXT)\\n\",\n \" - Educational Option Type (TEXT)\\n\",\n \" - NSLP Provision Status (TEXT)\\n\",\n \" - Charter School (Y/N) (INTEGER)\\n\",\n \" - Charter School Number (TEXT)\\n\",\n \" - Charter Funding Type (TEXT)\\n\",\n \" - IRC (INTEGER)\\n\",\n \" - Low Grade (TEXT)\\n\",\n \" - High Grade (TEXT)\\n\",\n \" - Enrollment (K-12) (REAL)\\n\",\n \" - Free Meal Count (K-12) (REAL)\\n\",\n \" - Percent (%) Eligible Free (K-12) (REAL)\\n\",\n \" - FRPM Count (K-12) (REAL)\\n\",\n \" - Percent (%) Eligible FRPM (K-12) (REAL)\\n\",\n \" - Enrollment (Ages 5-17) (REAL)\\n\",\n \" - Free Meal Count (Ages 5-17) (REAL)\\n\",\n \" - Percent (%) Eligible Free (Ages 5-17) (REAL)\\n\",\n \" - FRPM Count (Ages 5-17) (REAL)\\n\",\n \" - Percent (%) Eligible FRPM (Ages 5-17) (REAL)\\n\",\n \" - 2013-14 CALPADS Fall 1 Certification Status (INTEGER)\\n\",\n \"\\n\",\n \"Table: satscores\\n\",\n \"Columns:\\n\",\n \" - cds (TEXT) [PRIMARY KEY, FK -> schools.CDSCode]\\n\",\n \" - rtype (TEXT) [NOT NULL]\\n\",\n \" - sname (TEXT)\\n\",\n \" - dname (TEXT)\\n\",\n \" - cname (TEXT)\\n\",\n \" - enroll12 (INTEGER) [NOT NULL]\\n\",\n \" - NumTstTakr (INTEGER) [NOT NULL]\\n\",\n \" - AvgScrRead (INTEGER)\\n\",\n \" - AvgScrMath (INTEGER)\\n\",\n \" - AvgScrWrite (INTEGER)\\n\",\n \" - NumGE1500 (INTEGER)\\n\",\n \"\\n\",\n \"Table: schools\\n\",\n \"Columns:\\n\",\n \" - CDSCode (TEXT) [PRIMARY KEY]\\n\",\n \" - NCESDist (TEXT)\\n\",\n \" - NCESSchool (TEXT)\\n\",\n \" - StatusType (TEXT) [NOT NULL]\\n\",\n \" - County (TEXT) [NOT NULL]\\n\",\n \" - District (TEXT) [NOT NULL]\\n\",\n \" - School (TEXT)\\n\",\n \" - Street (TEXT)\\n\",\n \" - StreetAbr (TEXT)\\n\",\n \" - City (TEXT)\\n\",\n \" - Zip (TEXT)\\n\",\n \" - State (TEXT)\\n\",\n \" - MailStreet (TEXT)\\n\",\n \" - MailStrAbr (TEXT)\\n\",\n \" - MailCity (TEXT)\\n\",\n \" - MailZip (TEXT)\\n\",\n \" - MailState (TEXT)\\n\",\n \" - Phone (TEXT)\\n\",\n \" - Ext (TEXT)\\n\",\n \" - Website (TEXT)\\n\",\n \" - OpenDate (DATE)\\n\",\n \" - ClosedDate (DATE)\\n\",\n \" - Charter (INTEGER)\\n\",\n \" - CharterNum (TEXT)\\n\",\n \" - FundingType (TEXT)\\n\",\n \" - DOC (TEXT) [NOT NULL]\\n\",\n \" - DOCType (TEXT) [NOT NULL]\\n\",\n \" - SOC (TEXT)\\n\",\n \" - SOCType (TEXT)\\n\",\n \" - EdOpsCode (TEXT)\\n\",\n \" \\n\",\n \"\\n\",\n \"... (total 2401 characters)\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Format schema for prompt\\n\",\n \"schema_text = format_schema_for_prompt(schema, TEST_DB)\\n\",\n \"print(schema_text[:2000])\\n\",\n \"print(f\\\"\\\\n... (total {len(schema_text)} characters)\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8e904509\",\n \"metadata\": {},\n \"source\": [\n \"## 2. Load Prompts from External Modules\\n\",\n \"\\n\",\n \"Prompts are now defined in `configs/column_level_prompts.py`.\\n\",\n \"- **JSON format** is used (more structured, requires max_tokens=4000)\\n\",\n \"- Parser auto-detects format and handles both JSON and Plain Text\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 8,\n \"id\": \"1a425645\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Loaded from external modules:\\n\",\n \" - COLUMN_LEVEL_SYSTEM_PROMPT (2734 chars)\\n\",\n \" - COLUMN_LEVEL_USER_PROMPT_TEMPLATE\\n\",\n \" - DEFAULT_MAX_TOKENS = 4000\\n\",\n \" - parse_column_level_roles (auto-detects JSON/Text)\\n\",\n \" - validate_roles_against_schema\\n\",\n \"\\n\",\n \"--- System Prompt Preview ---\\n\",\n \"You are a database security expert specializing in fine-grained Role-Based Access Control (RBAC).\\n\",\n \"Your job is to read a relational database schema and propose a COHERENT set of roles with COLUMN-LEVEL permissions.\\n\",\n \"\\n\",\n \"Key goals:\\n\",\n \"- Minimize role count while covering real-world workflows (decide number of roles according to real world scenario).\\n\",\n \"- Each role must be clearly related to others (same scenario, complementary duties).\\n\",\n \"- Enforce least-privilege at the COLUMN level (specify which columns eac\\n\",\n \"...\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Reload modules to get latest changes\\n\",\n \"import importlib\\n\",\n \"import configs.column_level_prompts\\n\",\n \"import src.role_parser.column_level_parser\\n\",\n \"importlib.reload(configs.column_level_prompts)\\n\",\n \"importlib.reload(src.role_parser.column_level_parser)\\n\",\n \"\\n\",\n \"# Import prompts and parser from external modules\\n\",\n \"from configs.column_level_prompts import (\\n\",\n \" COLUMN_LEVEL_SYSTEM_PROMPT, \\n\",\n \" COLUMN_LEVEL_USER_PROMPT_TEMPLATE,\\n\",\n \" DEFAULT_MAX_TOKENS\\n\",\n \")\\n\",\n \"from src.role_parser import parse_column_level_roles, validate_roles_against_schema\\n\",\n \"\\n\",\n \"print(\\\"✓ Loaded from external modules:\\\")\\n\",\n \"print(f\\\" - COLUMN_LEVEL_SYSTEM_PROMPT ({len(COLUMN_LEVEL_SYSTEM_PROMPT)} chars)\\\")\\n\",\n \"print(f\\\" - COLUMN_LEVEL_USER_PROMPT_TEMPLATE\\\")\\n\",\n \"print(f\\\" - DEFAULT_MAX_TOKENS = {DEFAULT_MAX_TOKENS}\\\")\\n\",\n \"print(f\\\" - parse_column_level_roles (auto-detects JSON/Text)\\\")\\n\",\n \"print(f\\\" - validate_roles_against_schema\\\")\\n\",\n \"\\n\",\n \"print(\\\"\\\\n--- System Prompt Preview ---\\\")\\n\",\n \"print(COLUMN_LEVEL_SYSTEM_PROMPT[:500])\\n\",\n \"print(\\\"...\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"0acacb6e\",\n \"metadata\": {},\n \"source\": [\n \"## [Archived] Single-Sample Experiments\\n\",\n \"\\n\",\n \"The following code block contains single sample test code for debugging prompt and parser.\\n\",\n \"**Commented out. For production, skip to Section 8 for batch processing.**\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 9,\n \"id\": \"e9700ae1\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"⏭️ This cell is commented out. Skip to Section 8 for batch processing.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# ============================================================\\n\",\n \"# [ARCHIVED] Single sample experiment code - commented out, skip this cell\\n\",\n \"# ============================================================\\n\",\n \"# The following code is for testing and debugging a single database\\n\",\n \"# For production, skip to Section 8 for batch processing\\n\",\n \"\\n\",\n \"'''\\n\",\n \"# --- 3. Generate Column-Level Roles (Single DB) ---\\n\",\n \"print(\\\"Generating column-level roles...\\\")\\n\",\n \"user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=schema_text)\\n\",\n \"response = oracle.query(\\n\",\n \" prompt_sys=COLUMN_LEVEL_SYSTEM_PROMPT,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3, top_p=0.9,\\n\",\n \" max_completion_tokens=DEFAULT_MAX_TOKENS\\n\",\n \")\\n\",\n \"llm_response = response['answer']\\n\",\n \"print(f\\\"Response length: {len(llm_response)} chars\\\")\\n\",\n \"\\n\",\n \"# --- 4. Parse and Validate ---\\n\",\n \"from src.role_parser.column_level_parser import parse_column_level_roles\\n\",\n \"parsed_roles = parse_column_level_roles(llm_response)\\n\",\n \"print(f\\\"Parsed {len(parsed_roles)} roles\\\")\\n\",\n \"\\n\",\n \"validation = validate_roles_against_schema(parsed_roles, str(db_path))\\n\",\n \"print(f\\\"Valid: {validation['valid_roles']}/{validation['total_roles']}\\\")\\n\",\n \"\\n\",\n \"# --- 5. Show Results ---\\n\",\n \"for role in parsed_roles:\\n\",\n \" print(f\\\" - {role['role']}: {len(role.get('columns', {}))} tables\\\")\\n\",\n \"\\n\",\n \"# --- 6. Compare with Table-Level ---\\n\",\n \"from configs.prompts import SYSTEM_PROMPT as TABLE_LEVEL_PROMPT, USER_PROMPT_TEMPLATE\\n\",\n \"table_level_response = oracle.query(\\n\",\n \" prompt_sys=TABLE_LEVEL_PROMPT,\\n\",\n \" prompt_user=USER_PROMPT_TEMPLATE.format(schema_content=schema_text),\\n\",\n \" temp=0.3, top_p=0.9\\n\",\n \")\\n\",\n \"print(\\\"Table-Level Response:\\\", table_level_response['answer'][:500])\\n\",\n \"\\n\",\n \"# --- 7. Save Single DB Result ---\\n\",\n \"def convert_to_assignment_format(parsed_roles, db_name):\\n\",\n \" return {\\\"assignments\\\": {db_name: [\\n\",\n \" {\\\"role\\\": r[\\\"role\\\"], \\\"description\\\": r.get(\\\"description\\\", \\\"\\\"), \\\"policy\\\": r.get(\\\"columns\\\", {})}\\n\",\n \" for r in parsed_roles\\n\",\n \" ]}}\\n\",\n \"\\n\",\n \"column_level_assignments = convert_to_assignment_format(parsed_roles, TEST_DB)\\n\",\n \"output_file = project_root / 'outputs' / 'column_level_role_assignments.json'\\n\",\n \"with open(output_file, 'w') as f:\\n\",\n \" json.dump(column_level_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \"print(f\\\"Saved to: {output_file}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ This cell is commented out. Skip to Section 8 for batch processing.\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8bc8cb95\",\n \"metadata\": {},\n \"source\": [\n \"## 3. Batch Process All BIRD Databases\\n\",\n \"\\n\",\n \"Generate column-level role assignments for all BIRD databases with parallel processing.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 10,\n \"id\": \"fe3f2e81\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Configuration:\\n\",\n \" Workers: 40\\n\",\n \" Databases: 11\\n\",\n \" Max tokens: 4000\\n\",\n \" Model: deepseek-chat\\n\",\n \"\\n\",\n \"Databases to process:\\n\",\n \" - superhero\\n\",\n \" - thrombosis_prediction\\n\",\n \" - student_club\\n\",\n \" - toxicology\\n\",\n \" - california_schools\\n\",\n \" - debit_card_specializing\\n\",\n \" - card_games\\n\",\n \" - codebase_community\\n\",\n \" - formula_1\\n\",\n \" - european_football_2\\n\",\n \" - financial\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Batch processing configuration\\n\",\n \"from concurrent.futures import ThreadPoolExecutor, as_completed\\n\",\n \"from tqdm.notebook import tqdm\\n\",\n \"\\n\",\n \"# Configuration\\n\",\n \"WORKERS = 40\\n\",\n \"SAMPLES = 100 # 0 for all databases\\n\",\n \"MAX_TOKENS = DEFAULT_MAX_TOKENS\\n\",\n \"\\n\",\n \"# Get all BIRD databases\\n\",\n \"all_dbs = [d.name for d in bird_db_dir.iterdir() if d.is_dir()]\\n\",\n \"if SAMPLES > 0:\\n\",\n \" all_dbs = all_dbs[:SAMPLES]\\n\",\n \"\\n\",\n \"print(f\\\"Configuration:\\\")\\n\",\n \"print(f\\\" Workers: {WORKERS}\\\")\\n\",\n \"print(f\\\" Databases: {len(all_dbs)}\\\")\\n\",\n \"print(f\\\" Max tokens: {MAX_TOKENS}\\\")\\n\",\n \"print(f\\\" Model: {MODEL}\\\")\\n\",\n \"print(f\\\"\\\\nDatabases to process:\\\")\\n\",\n \"for db in all_dbs:\\n\",\n \" print(f\\\" - {db}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 11,\n \"id\": \"7b5edd94\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Helper functions defined\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Helper functions for batch processing\\n\",\n \"\\n\",\n \"def process_single_database(db_name: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Process a single database and return role assignments.\\\"\\\"\\\"\\n\",\n \" db_path = bird_db_dir / db_name / f\\\"{db_name}.sqlite\\\"\\n\",\n \" \\n\",\n \" if not db_path.exists():\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": f\\\"Database not found\\\"}\\n\",\n \" \\n\",\n \" try:\\n\",\n \" # Extract schema\\n\",\n \" db_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" db_schema_text = format_schema_for_prompt(db_schema, db_name)\\n\",\n \" \\n\",\n \" # Generate roles via LLM\\n\",\n \" user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=db_schema_text)\\n\",\n \" \\n\",\n \" response = oracle.query(\\n\",\n \" prompt_sys=COLUMN_LEVEL_SYSTEM_PROMPT,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3,\\n\",\n \" top_p=0.9,\\n\",\n \" max_completion_tokens=MAX_TOKENS\\n\",\n \" )\\n\",\n \" \\n\",\n \" llm_response = response['answer']\\n\",\n \" usage = response.get('usage', {})\\n\",\n \" \\n\",\n \" # Parse response\\n\",\n \" roles = parse_column_level_roles(llm_response)\\n\",\n \" \\n\",\n \" if not roles:\\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"parse_error\\\",\\n\",\n \" \\\"error\\\": \\\"Failed to parse LLM response\\\",\\n\",\n \" \\\"raw_response\\\": llm_response[:300]\\n\",\n \" }\\n\",\n \" \\n\",\n \" # Validate against schema\\n\",\n \" validation = validate_roles_against_schema(roles, str(db_path))\\n\",\n \" \\n\",\n \" # Convert to target format\\n\",\n \" assignments = []\\n\",\n \" for role in roles:\\n\",\n \" assignments.append({\\n\",\n \" \\\"role\\\": role[\\\"role\\\"],\\n\",\n \" \\\"description\\\": role.get(\\\"description\\\", \\\"\\\"),\\n\",\n \" \\\"policy\\\": role.get(\\\"columns\\\", {})\\n\",\n \" })\\n\",\n \" \\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"success\\\",\\n\",\n \" \\\"roles_count\\\": len(assignments),\\n\",\n \" \\\"valid_roles\\\": validation['valid_roles'],\\n\",\n \" \\\"all_valid\\\": validation['all_valid'],\\n\",\n \" \\\"assignments\\\": assignments,\\n\",\n \" \\\"usage\\\": usage\\n\",\n \" }\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"error\\\",\\n\",\n \" \\\"error\\\": str(e)\\n\",\n \" }\\n\",\n \"\\n\",\n \"print(\\\"✓ Helper functions defined\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 12,\n \"id\": \"61e61795\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Starting batch processing with 40 workers...\\n\",\n \"============================================================\\n\",\n \"[1/11] ✓ toxicology: 4 roles (4 valid)\\n\",\n \"[2/11] ✓ debit_card_specializing: 4 roles (4 valid)\\n\",\n \"[3/11] ✓ thrombosis_prediction: 4 roles (4 valid)\\n\",\n \"[4/11] ✓ student_club: 5 roles (5 valid)\\n\",\n \"[5/11] ✓ superhero: 5 roles (5 valid)\\n\",\n \"[6/11] ✓ financial: 5 roles (5 valid)\\n\",\n \"[7/11] ✓ card_games: 5 roles (5 valid)\\n\",\n \"[8/11] ✓ codebase_community: 4 roles (4 valid)\\n\",\n \"[9/11] ✓ california_schools: 5 roles (5 valid)\\n\",\n \"[10/11] ✓ formula_1: 5 roles (5 valid)\\n\",\n \"[11/11] ✓ european_football_2: 5 roles (5 valid)\\n\",\n \"============================================================\\n\",\n \"Completed: 11/11 success, 0 errors\\n\",\n \"Total tokens: 25,679\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Execute batch processing with parallel workers\\n\",\n \"print(f\\\"Starting batch processing with {WORKERS} workers...\\\")\\n\",\n \"print(\\\"=\\\" * 60)\\n\",\n \"\\n\",\n \"results = {\\n\",\n \" \\\"metadata\\\": {\\n\",\n \" \\\"model\\\": MODEL,\\n\",\n \" \\\"max_tokens\\\": MAX_TOKENS,\\n\",\n \" \\\"total_databases\\\": len(all_dbs)\\n\",\n \" },\\n\",\n \" \\\"assignments\\\": {},\\n\",\n \" \\\"errors\\\": []\\n\",\n \"}\\n\",\n \"\\n\",\n \"success_count = 0\\n\",\n \"error_count = 0\\n\",\n \"total_tokens = {\\\"prompt\\\": 0, \\\"completion\\\": 0}\\n\",\n \"\\n\",\n \"with ThreadPoolExecutor(max_workers=WORKERS) as executor:\\n\",\n \" futures = {executor.submit(process_single_database, db): db for db in all_dbs}\\n\",\n \" \\n\",\n \" for i, future in enumerate(as_completed(futures), 1):\\n\",\n \" db_name = futures[future]\\n\",\n \" try:\\n\",\n \" result = future.result()\\n\",\n \" \\n\",\n \" if result[\\\"status\\\"] == \\\"success\\\":\\n\",\n \" results[\\\"assignments\\\"][result[\\\"database\\\"]] = result[\\\"assignments\\\"]\\n\",\n \" success_count += 1\\n\",\n \" \\n\",\n \" usage = result.get(\\\"usage\\\", {})\\n\",\n \" total_tokens[\\\"prompt\\\"] += usage.get(\\\"prompt_tokens\\\", 0)\\n\",\n \" total_tokens[\\\"completion\\\"] += usage.get(\\\"completion_tokens\\\", 0)\\n\",\n \" \\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✓ {db_name}: {result['roles_count']} roles ({result['valid_roles']} valid)\\\")\\n\",\n \" else:\\n\",\n \" results[\\\"errors\\\"].append(result)\\n\",\n \" error_count += 1\\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✗ {db_name}: {result.get('error', result['status'])}\\\")\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" error_count += 1\\n\",\n \" results[\\\"errors\\\"].append({\\\"database\\\": db_name, \\\"error\\\": str(e)})\\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✗ {db_name}: {e}\\\")\\n\",\n \"\\n\",\n \"results[\\\"metadata\\\"][\\\"success_count\\\"] = success_count\\n\",\n \"results[\\\"metadata\\\"][\\\"error_count\\\"] = error_count\\n\",\n \"results[\\\"metadata\\\"][\\\"total_tokens\\\"] = total_tokens\\n\",\n \"\\n\",\n \"print(\\\"=\\\" * 60)\\n\",\n \"print(f\\\"Completed: {success_count}/{len(all_dbs)} success, {error_count} errors\\\")\\n\",\n \"print(f\\\"Total tokens: {total_tokens['prompt'] + total_tokens['completion']:,}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 13,\n \"id\": \"39d38aa3\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Results saved to: /home/feiy/Role-SQL-benchmark/outputs/column_level_role_assignments_bird.json\\n\",\n \"\\n\",\n \"File structure:\\n\",\n \" - metadata: model, tokens, counts\\n\",\n \" - assignments: 11 databases\\n\",\n \" - errors: 0 entries\\n\",\n \"\\n\",\n \"Sample (toxicology):\\n\",\n \"[\\n\",\n \" {\\n\",\n \" \\\"role\\\": \\\"MolecularResearcher\\\",\\n\",\n \" \\\"description\\\": \\\"Analyzes molecular structures and their components for research purposes\\\",\\n\",\n \" \\\"policy\\\": {\\n\",\n \" \\\"molecule\\\": [\\n\",\n \" \\\"molecule_id\\\",\\n\",\n \" \\\"label\\\"\\n\",\n \" ],\\n\",\n \" \\\"atom\\\": [\\n\",\n \" \\\"atom_id\\\",\\n\",\n \" \\\"molecule_id\\\",\\n\",\n \" \\\"element\\\"\\n\",\n \" ],\\n\",\n \" \\\"bond\\\": [\\n\",\n \" \\\"bond_id\\\",\\n\",\n \" \\\"molecule_id\\\",\\n\",\n \" \\\"bond_type\\\"\\n\",\n \" ],\\n\",\n \" \\\"connected\\\": [\\n\",\n \" \\\"atom_id\\\",\\n\",\n \" \\\"atom_id2\\\",\\n\",\n \" \\\"bond_id\\\"\\n\",\n \" ]\\n\",\n \" }\\n\",\n \" }\\n\",\n \"]\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Save batch results to file\\n\",\n \"output_file = project_root / 'outputs' / 'column_level_role_assignments_bird.json'\\n\",\n \"\\n\",\n \"with open(output_file, 'w', encoding='utf-8') as f:\\n\",\n \" json.dump(results, f, indent=2, ensure_ascii=False)\\n\",\n \"\\n\",\n \"print(f\\\"✓ Results saved to: {output_file}\\\")\\n\",\n \"print(f\\\"\\\\nFile structure:\\\")\\n\",\n \"print(f\\\" - metadata: model, tokens, counts\\\")\\n\",\n \"print(f\\\" - assignments: {len(results['assignments'])} databases\\\")\\n\",\n \"print(f\\\" - errors: {len(results['errors'])} entries\\\")\\n\",\n \"\\n\",\n \"# Show sample\\n\",\n \"if results['assignments']:\\n\",\n \" sample_db = list(results['assignments'].keys())[0]\\n\",\n \" print(f\\\"\\\\nSample ({sample_db}):\\\")\\n\",\n \" print(json.dumps(results['assignments'][sample_db][:1], indent=2, ensure_ascii=False)[:500])\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"9595c46d\",\n \"metadata\": {},\n \"source\": [\n \"## 4. Generate Column-Level RBAC Dataset\\n\",\n \"\\n\",\n \"Based on the generated role policies, combined with BIRD dataset queries, generate the final RBAC training/evaluation dataset.\\n\",\n \"\\n\",\n \"Dataset format (consistent with table-level):\\n\",\n \"- `db_id`: Database name\\n\",\n \"- `instruction`: Full instruction with schema + evidence + role policy\\n\",\n \"- `role`: Role name\\n\",\n \"- `policy`: Column-level permission policy {table: [columns]}\\n\",\n \"- `input`: User question\\n\",\n \"- `output`: SQL or denial message\\n\",\n \"- `difficulty`: Query difficulty level\\n\",\n \"- `metadata`: Contains gold_sql, permission, query_columns, missing_columns, etc.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 45,\n \"id\": \"405783fa\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Dataset Generation Config ===\\n\",\n \"Role assignments: /home/feiy/Role-SQL-benchmark/outputs/column_level_role_assignments_bird.json\\n\",\n \"BIRD data file: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev.json\\n\",\n \"BIRD database dir: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev_databases\\n\",\n \"\\n\",\n \"✓ All file paths are valid\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 4.1 Import generator and test dependencies\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator, format_policy_text\\n\",\n \"from src.processors.column_extractor import extract_query_columns\\n\",\n \"from src.processors.column_permission_checker import check_column_permission\\n\",\n \"import glob\\n\",\n \"\\n\",\n \"# Configure paths - use 2025 version (dev_20251106) for latest BIRD data\\n\",\n \"ROLE_ASSIGNMENTS_PATH = project_root / 'outputs' / 'column_level_role_assignments_bird.json'\\n\",\n \"BIRD_DATA_PATH = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev.json'\\n\",\n \"BIRD_DB_ROOT = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases'\\n\",\n \"\\n\",\n \"print(\\\"=== Dataset Generation Config ===\\\")\\n\",\n \"print(f\\\"Role assignments: {ROLE_ASSIGNMENTS_PATH}\\\")\\n\",\n \"print(f\\\"BIRD data file: {BIRD_DATA_PATH}\\\")\\n\",\n \"print(f\\\"BIRD database dir: {BIRD_DB_ROOT}\\\")\\n\",\n \"\\n\",\n \"# Verify file existence\\n\",\n \"# assert ROLE_ASSIGNMENTS_PATH.exists(), f\\\"Role assignments file not found: {ROLE_ASSIGNMENTS_PATH}\\\"\\n\",\n \"assert BIRD_DATA_PATH.exists(), f\\\"BIRD data file not found: {BIRD_DATA_PATH}\\\"\\n\",\n \"assert BIRD_DB_ROOT.exists(), f\\\"BIRD database dir not found: {BIRD_DB_ROOT}\\\"\\n\",\n \"print(\\\"\\\\n✓ All file paths are valid\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4b80dc65\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== SQL Column Extraction Test ===\\n\",\n \"Tables: {'song', 'singer'}\\n\",\n \"Columns: {'song': {'singer_id', 'title'}, 'singer': {'id', 'name', 'country', 'age'}}\\n\",\n \"Has *: False\\n\",\n \"\\n\",\n \"=== Permission Check Test (Allow) ===\\n\",\n \"Allowed: True\\n\",\n \"Reason: All required columns are permitted\\n\",\n \"\\n\",\n \"=== Permission Check Test (Deny) ===\\n\",\n \"Allowed: False\\n\",\n \"Reason: Missing column permissions: song: singer_id; singer: age, country, id\\n\",\n \"Missing: {'song': {'singer_id'}, 'singer': {'id', 'country', 'age'}}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.2 Test SQL column extraction and permission checking\\n\",\n \"# Verified working, archived to simplify notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"test_sql = \\\"\\\"\\\"\\n\",\n \"SELECT singer.name, singer.age, song.title\\n\",\n \"FROM singer\\n\",\n \"JOIN song ON singer.id = song.singer_id\\n\",\n \"WHERE singer.country = 'USA'\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"print(\\\"=== SQL Column Extraction Test ===\\\")\\n\",\n \"info = extract_query_columns(test_sql)\\n\",\n \"print(f\\\"Tables: {info.tables}\\\")\\n\",\n \"print(f\\\"Columns: {info.columns}\\\")\\n\",\n \"print(f\\\"Has *: {info.has_star}\\\")\\n\",\n \"\\n\",\n \"# Test permission checking\\n\",\n \"policy_allow = {\\n\",\n \" 'singer': ['name', 'age', 'country', 'id'],\\n\",\n \" 'song': ['title', 'singer_id']\\n\",\n \"}\\n\",\n \"policy_deny = {\\n\",\n \" 'singer': ['name'], # Missing 'age', 'country', 'id'\\n\",\n \" 'song': ['title'] # Missing 'singer_id'\\n\",\n \"}\\n\",\n \"\\n\",\n \"print(\\\"\\\\n=== Permission Check Test (Allow) ===\\\")\\n\",\n \"result1 = check_column_permission(test_sql, policy_allow)\\n\",\n \"print(f\\\"Allowed: {result1.allowed}\\\")\\n\",\n \"print(f\\\"Reason: {result1.reason}\\\")\\n\",\n \"\\n\",\n \"print(\\\"\\\\n=== Permission Check Test (Deny) ===\\\")\\n\",\n \"result2 = check_column_permission(test_sql, policy_deny)\\n\",\n \"print(f\\\"Allowed: {result2.allowed}\\\")\\n\",\n \"print(f\\\"Reason: {result2.reason}\\\")\\n\",\n \"print(f\\\"Missing: {result2.missing_columns}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Column extraction/permission tests - verified\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 16,\n \"id\": \"0a018208\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Generator Initialized ===\\n\",\n \"Total BIRD queries: 1534\\n\",\n \"Databases with role assignments: 11\\n\",\n \"Databases with queries: 11\\n\",\n \"\\n\",\n \"Queries per database:\\n\",\n \" california_schools: 89\\n\",\n \" card_games: 191\\n\",\n \" codebase_community: 186\\n\",\n \" debit_card_specializing: 64\\n\",\n \" european_football_2: 129\\n\",\n \" financial: 106\\n\",\n \" formula_1: 174\\n\",\n \" student_club: 158\\n\",\n \" superhero: 129\\n\",\n \" thrombosis_prediction: 163\\n\",\n \" toxicology: 145\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 4.3 Initialize generator\\n\",\n \"generator = ColumnLevelRBACGenerator(\\n\",\n \" role_assignments_path=str(ROLE_ASSIGNMENTS_PATH),\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH),\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" project_root=str(project_root),\\n\",\n \" seed=42\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"=== Generator Initialized ===\\\")\\n\",\n \"print(f\\\"Total BIRD queries: {len(generator.bird_data)}\\\")\\n\",\n \"print(f\\\"Databases with role assignments: {len(generator.role_assignments.get('assignments', {}))}\\\")\\n\",\n \"print(f\\\"Databases with queries: {len(generator.queries_by_db)}\\\")\\n\",\n \"\\n\",\n \"# Show query counts per database\\n\",\n \"print(\\\"\\\\nQueries per database:\\\")\\n\",\n \"for db_id, queries in sorted(generator.queries_by_db.items()):\\n\",\n \" print(f\\\" {db_id}: {len(queries)}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"2a267246\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Generating Sample Dataset ===\\n\",\n \"Generating column-level RBAC dataset...\\n\",\n \" Roles per DB: 1\\n\",\n \" Queries per role: 3\\n\",\n \"Current ratio (allowed): 60.61%\\n\",\n \" Allowed: 20, Denied: 13\\n\",\n \"\\n\",\n \"Dataset saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_sample.json\\n\",\n \"Metadata saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_sample_metadata.json\\n\",\n \" Total entries: 33\\n\",\n \" Allowed: 20 (60.6%)\\n\",\n \" Denied: 13 (39.4%)\\n\",\n \"\\n\",\n \"Statistics:\\n\",\n \" total_entries: 33\\n\",\n \" allowed: 20\\n\",\n \" denied: 13\\n\",\n \" allowed_ratio: 0.6060606060606061\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.4 Generate sample dataset (for format validation)\\n\",\n \"# Sample dataset used for debugging, production uses 4.5\\n\",\n \"\\n\",\n \"'''\\n\",\n \"print(\\\"=== Generating Sample Dataset ===\\\")\\n\",\n \"sample_stats = generator.generate_and_save(\\n\",\n \" output_path=str(project_root / 'outputs' / 'column_level_rbac_dataset_bird_sample.json'),\\n\",\n \" roles_per_db=1, # Use only 1 role per database\\n\",\n \" queries_per_role=3 # Use only 3 queries per role\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"\\\\\\\\nStatistics:\\\")\\n\",\n \"for k, v in sample_stats.items():\\n\",\n \" if k != 'by_database':\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Sample dataset generation - production uses 4.5\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4851fde0\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Data Format Validation ===\\n\",\n \"Total entries: 33\\n\",\n \"\\n\",\n \"--- Allowed Entry Example ---\\n\",\n \"db_id: toxicology\\n\",\n \"role: MolecularResearcher\\n\",\n \"policy: {\\\"molecule\\\": [\\\"molecule_id\\\", \\\"label\\\"], \\\"atom\\\": [\\\"atom_id\\\", \\\"molecule_id\\\", \\\"element\\\"], \\\"bond\\\": [\\\"bond...\\n\",\n \"input: What are the atom IDs of the bond TR000_2_5?...\\n\",\n \"output: SELECT T.atom_id FROM connected AS T WHERE T.bond_id = 'TR000_2_5'...\\n\",\n \"difficulty: simple\\n\",\n \"instruction length: 1887 chars\\n\",\n \"\\n\",\n \"--- Denied Entry Example ---\\n\",\n \"db_id: thrombosis_prediction\\n\",\n \"role: ClinicalResearcher\\n\",\n \"input: How old was the patient who had the highest hemoglobin count on the date of labo...\\n\",\n \"output: Sorry, I cannot answer.\\n\",\n \"missing_columns: {'patient': ['Diagnosis']}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.5-4.6 Validate generated data format & Show instruction example\\n\",\n \"# Data format verified, archived to simplify notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"sample_file = project_root / 'outputs' / 'column_level_rbac_dataset_bird_sample.json'\\n\",\n \"with open(sample_file, 'r') as f:\\n\",\n \" sample_data = json.load(f)\\n\",\n \"\\n\",\n \"print(\\\"=== Data Format Validation ===\\\")\\n\",\n \"print(f\\\"Total entries: {len(sample_data)}\\\")\\n\",\n \"\\n\",\n \"allowed_entry = next((e for e in sample_data if e['metadata']['permission'] == 'allowed'), None)\\n\",\n \"denied_entry = next((e for e in sample_data if e['metadata']['permission'] == 'denied'), None)\\n\",\n \"\\n\",\n \"if allowed_entry:\\n\",\n \" print(\\\"\\\\\\\\n--- Allowed Entry Example ---\\\")\\n\",\n \" print(f\\\"db_id: {allowed_entry['db_id']}\\\")\\n\",\n \" print(f\\\"role: {allowed_entry['role']}\\\")\\n\",\n \" print(f\\\"policy: {json.dumps(allowed_entry['policy'])[:100]}...\\\")\\n\",\n \" print(f\\\"input: {allowed_entry['input'][:80]}...\\\")\\n\",\n \" print(f\\\"output: {allowed_entry['output'][:80]}...\\\")\\n\",\n \"\\n\",\n \"if denied_entry:\\n\",\n \" print(\\\"\\\\\\\\n--- Denied Entry Example ---\\\")\\n\",\n \" print(f\\\"db_id: {denied_entry['db_id']}\\\")\\n\",\n \" print(f\\\"role: {denied_entry['role']}\\\")\\n\",\n \" print(f\\\"output: {denied_entry['output']}\\\")\\n\",\n \" print(f\\\"missing_columns: {denied_entry['metadata']['missing_columns']}\\\")\\n\",\n \"\\n\",\n \"# Show full instruction\\n\",\n \"print(\\\"\\\\\\\\n=== Full Instruction Example ===\\\")\\n\",\n \"if allowed_entry:\\n\",\n \" print(allowed_entry['instruction'][:2500])\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Data format validation - verified\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"c05e8787\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Generating Full Column-Level RBAC Dataset ===\\n\",\n \"Output: /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251224.json\\n\",\n \"Note: Using updated column_extractor with CTE fix\\n\",\n \"Generating column-level RBAC dataset...\\n\",\n \" Roles per DB: None\\n\",\n \" Queries per role: all\\n\",\n \"Current ratio (allowed): 61.18%\\n\",\n \" Allowed: 4351, Denied: 2761\\n\",\n \"\\n\",\n \"Dataset saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251224.json\\n\",\n \"Metadata saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251224_metadata.json\\n\",\n \" Total entries: 7112\\n\",\n \" Allowed: 4351 (61.2%)\\n\",\n \" Denied: 2761 (38.8%)\\n\",\n \"\\n\",\n \"Full dataset statistics:\\n\",\n \" total_entries: 7112\\n\",\n \" allowed: 4351\\n\",\n \" denied: 2761\\n\",\n \" allowed_ratio: 0.6117829021372329\\n\",\n \"\\n\",\n \"Per-database distribution:\\n\",\n \" toxicology: allowed=580, denied=0\\n\",\n \" debit_card_specializing: allowed=223, denied=33\\n\",\n \" thrombosis_prediction: allowed=432, denied=220\\n\",\n \" student_club: allowed=396, denied=394\\n\",\n \" superhero: allowed=328, denied=317\\n\",\n \" financial: allowed=212, denied=318\\n\",\n \" card_games: allowed=507, denied=448\\n\",\n \" codebase_community: allowed=669, denied=75\\n\",\n \" california_schools: allowed=173, denied=272\\n\",\n \" formula_1: allowed=553, denied=317\\n\",\n \" european_football_2: allowed=278, denied=367\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 4.5 Generate Full Column-Level RBAC Dataset\\n\",\n \"from datetime import datetime\\n\",\n \"\\n\",\n \"# Reload the modules to ensure we use the latest CTE fix\\n\",\n \"import importlib\\n\",\n \"import src.processors.column_extractor\\n\",\n \"import src.processors.column_permission_checker\\n\",\n \"import src.processors.column_level_rbac_generator\\n\",\n \"\\n\",\n \"importlib.reload(src.processors.column_extractor)\\n\",\n \"importlib.reload(src.processors.column_permission_checker)\\n\",\n \"importlib.reload(src.processors.column_level_rbac_generator)\\n\",\n \"\\n\",\n \"# Re-import with fresh code\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator\\n\",\n \"\\n\",\n \"# Re-create generator with fresh modules\\n\",\n \"generator = ColumnLevelRBACGenerator(\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" role_assignments_path=str(ROLE_ASSIGNMENTS_PATH),\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH)\\n\",\n \")\\n\",\n \"\\n\",\n \"# Output with date suffix\\n\",\n \"today = datetime.now().strftime('%Y%m%d')\\n\",\n \"output_path = project_root / 'outputs' / f'column_level_rbac_dataset_bird_{today}.json'\\n\",\n \"\\n\",\n \"print(\\\"=== Generating Full Column-Level RBAC Dataset ===\\\")\\n\",\n \"print(f\\\"Output: {output_path}\\\")\\n\",\n \"\\n\",\n \"full_stats = generator.generate_and_save(\\n\",\n \" output_path=str(output_path),\\n\",\n \" roles_per_db=None, # Use all roles (number varies per db based on LLM generation)\\n\",\n \" queries_per_role=None # Use all queries\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"\\\\nFull dataset statistics:\\\")\\n\",\n \"for k, v in full_stats.items():\\n\",\n \" if k == 'by_database':\\n\",\n \" print(f\\\"\\\\nPer-database distribution:\\\")\\n\",\n \" for db_id, counts in v.items():\\n\",\n \" print(f\\\" {db_id}: allowed={counts['allowed']}, denied={counts['denied']}\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" {k}: {v}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"2142ac6e\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Comparison with Table-Level Data Format ===\\n\",\n \"\\n\",\n \"--- Table-Level Entry Fields ---\\n\",\n \"['db_id', 'difficulty', 'input', 'instruction', 'metadata', 'output', 'role', 'tables']\\n\",\n \"\\n\",\n \"--- Column-Level Entry Fields ---\\n\",\n \"['db_id', 'difficulty', 'input', 'instruction', 'metadata', 'output', 'policy', 'role']\\n\",\n \"\\n\",\n \"Common fields: {'output', 'role', 'metadata', 'difficulty', 'db_id', 'input', 'instruction'}\\n\",\n \"Table-Level only: {'tables'}\\n\",\n \"Column-Level only: {'policy'}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.6 Compare with Table-Level format\\n\",\n \"# Format comparison completed, archived to simplify notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"print(\\\"=== Comparison with Table-Level Data Format ===\\\")\\n\",\n \"\\n\",\n \"table_level_file = project_root / 'data' / 'selected' / 'bird' / 'bird_dev_with_role_rbac.json'\\n\",\n \"if table_level_file.exists():\\n\",\n \" with open(table_level_file, 'r') as f:\\n\",\n \" table_level_data = json.load(f)\\n\",\n \" \\n\",\n \" print(\\\"\\\\\\\\n--- Table-Level Entry Fields ---\\\")\\n\",\n \" print(sorted(table_level_data[0].keys()))\\n\",\n \" \\n\",\n \" print(\\\"\\\\\\\\n--- Column-Level Entry Fields ---\\\") \\n\",\n \" print(sorted(sample_data[0].keys()))\\n\",\n \" \\n\",\n \" tl_keys = set(table_level_data[0].keys())\\n\",\n \" cl_keys = set(sample_data[0].keys())\\n\",\n \" \\n\",\n \" print(f\\\"\\\\\\\\nCommon fields: {tl_keys & cl_keys}\\\")\\n\",\n \" print(f\\\"Table-Level only: {tl_keys - cl_keys}\\\")\\n\",\n \" print(f\\\"Column-Level only: {cl_keys - tl_keys}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Table-level comparison - format verified compatible\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"7392ebc1\",\n \"metadata\": {},\n \"source\": [\n \"## 5. Role Generation Quality Assessment\\n\",\n \"\\n\",\n \"Automated quality checks for generated role files and RBAC datasets.\\n\",\n \"\\n\",\n \"### Quality Metrics\\n\",\n \"\\n\",\n \"| Metric | Healthy Range | Issue Description |\\n\",\n \"|--------|---------------|-------------------|\\n\",\n \"| **Deny Rate** | 5% - 90% | <5% too permissive, >90% too restrictive |\\n\",\n \"| **All-Allow Queries** | <50% | High value indicates poor role differentiation |\\n\",\n \"| **Role-Schema Similarity** | >0.6 | <0.6 indicates poor semantic alignment |\\n\",\n \"| **Policy Overlap** | <70% | >70% indicates redundant roles |\\n\",\n \"| **Coverage Diversity** | std >0.1 | Low std indicates roles have similar permissions |\\n\",\n \"\\n\",\n \"### Evaluation Pipeline\\n\",\n \"1. **Deny Rate Analysis**: Check permission distribution balance\\n\",\n \"2. **Semantic Quality**: Embedding-based role-schema alignment\\n\",\n \"3. **Policy Overlap**: Jaccard similarity to detect redundant roles\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 73,\n \"id\": \"71f8f60f\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Quality Thresholds (Configurable for BIRD) ===\\n\",\n \" deny_rate_min: 5.0\\n\",\n \" coverage_max: 0.85\\n\",\n \" coverage_std_min: 0.065\\n\",\n \" max_overlap: 0.8\\n\",\n \" embed_model: text-embedding-3-small\\n\",\n \" embed_backend: auto\\n\",\n \"\\n\",\n \"Role Assignments: bird_column_level_rbac_assignments_v2_20251230.json\\n\",\n \"Dataset: column_level_rbac_dataset_bird_20251230.json\\n\",\n \"Schema Dir: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev_databases\\n\",\n \"\\n\",\n \"✓ Quality evaluator initialized with custom thresholds\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 5.1 Setup Quality Evaluator (force reload all modules)\\n\",\n \"import importlib\\n\",\n \"import sys\\n\",\n \"from pathlib import Path\\n\",\n \"import glob\\n\",\n \"\\n\",\n \"# Force reload the entire module tree\\n\",\n \"if 'src.role_evaluator.quality_metrics' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator.quality_metrics']\\n\",\n \"if 'src.role_evaluator.quality_visualizer' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator.quality_visualizer']\\n\",\n \"if 'src.role_evaluator' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator']\\n\",\n \"\\n\",\n \"from src.role_evaluator import RoleQualityEvaluator, RoleQualityVisualizer, print_quality_report\\n\",\n \"\\n\",\n \"# Configure paths\\n\",\n \"project_root = Path.cwd().parent if Path.cwd().name == 'notebooks' else Path.cwd()\\n\",\n \"\\n\",\n \"# Find most recent dataset and role assignments files\\n\",\n \"role_files = sorted(glob.glob(str(project_root / 'outputs' / 'column_level_role_assignments_bird_*.json')))\\n\",\n \"ROLE_ASSIGNMENTS_PATH = role_files[-1] if role_files else str(project_root / 'outputs' / 'column_level_role_assignments_bird.json')\\n\",\n \"\\n\",\n \"# Check for v2 role assignments (after regeneration)\\n\",\n \"role_files_v2 = sorted([f for f in glob.glob(str(project_root / 'outputs' / 'bird_column_level_rbac_assignments_*.json'))\\n\",\n \" if 'v2' in f])\\n\",\n \"if role_files_v2:\\n\",\n \" ROLE_ASSIGNMENTS_PATH = role_files_v2[-1]\\n\",\n \"\\n\",\n \"dataset_files = sorted([f for f in glob.glob(str(project_root / 'outputs' / 'column_level_rbac_dataset_bird_*.json')) \\n\",\n \" if 'metadata' not in f])\\n\",\n \"if not dataset_files:\\n\",\n \" raise FileNotFoundError(\\\"No RBAC dataset found in outputs/\\\")\\n\",\n \"DATASET_PATH = dataset_files[-1]\\n\",\n \"\\n\",\n \"SCHEMA_DIR = str(project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases')\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# CONFIGURABLE QUALITY THRESHOLDS\\n\",\n \"# Adjust based on dataset characteristics\\n\",\n \"# BIRD has larger DBs with more columns, so thresholds differ from Spider\\n\",\n \"# ============================================================\\n\",\n \"QUALITY_THRESHOLDS = {\\n\",\n \" \\\"deny_rate_min\\\": 5.0, # Warn if deny rate < this (roles too permissive)\\n\",\n \" \\\"coverage_max\\\": 0.85, # Warn if avg coverage > this (roles too broad)\\n\",\n \" \\\"coverage_std_min\\\": 0.065, # Warn if coverage std < this (low diversity)\\n\",\n \" \\\"max_overlap\\\": 0.80, # Warn if max overlap > this (redundant roles)\\n\",\n \"}\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EMBEDDING MODEL CONFIGURATION\\n\",\n \"# Backend auto-detected based on model name, or set explicitly\\n\",\n \"# ============================================================\\n\",\n \"# OpenAI models (requires OPENAI_API_KEY):\\n\",\n \"# - \\\"text-embedding-3-small\\\" (default, cost-effective)\\n\",\n \"# - \\\"text-embedding-3-large\\\" (higher accuracy)\\n\",\n \"# - \\\"text-embedding-ada-002\\\" (legacy)\\n\",\n \"# \\n\",\n \"# BAAI/fastembed models (local, no API key needed):\\n\",\n \"# - \\\"BAAI/bge-small-en-v1.5\\\" (fast, lightweight)\\n\",\n \"# - \\\"BAAI/bge-base-en-v1.5\\\" (balanced)\\n\",\n \"# - \\\"BAAI/bge-large-en-v1.5\\\" (best accuracy)\\n\",\n \"# ============================================================\\n\",\n \"# EMBED_MODEL = \\\"BAAI/bge-small-en-v1.5\\\"\\n\",\n \"EMBED_MODEL = \\\"text-embedding-3-small\\\"\\n\",\n \"EMBED_BACKEND = None # None = auto-detect, or \\\"openai\\\" / \\\"fastembed\\\"\\n\",\n \"\\n\",\n \"print(\\\"=== Quality Thresholds (Configurable for BIRD) ===\\\")\\n\",\n \"for k, v in QUALITY_THRESHOLDS.items():\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"print(f\\\" embed_model: {EMBED_MODEL}\\\")\\n\",\n \"print(f\\\" embed_backend: {EMBED_BACKEND or 'auto'}\\\")\\n\",\n \"\\n\",\n \"print(f\\\"\\\\nRole Assignments: {Path(ROLE_ASSIGNMENTS_PATH).name if ROLE_ASSIGNMENTS_PATH else 'Not found'}\\\")\\n\",\n \"print(f\\\"Dataset: {Path(DATASET_PATH).name if DATASET_PATH else 'Not found'}\\\")\\n\",\n \"print(f\\\"Schema Dir: {SCHEMA_DIR}\\\")\\n\",\n \"\\n\",\n \"if ROLE_ASSIGNMENTS_PATH and DATASET_PATH:\\n\",\n \" evaluator = RoleQualityEvaluator(\\n\",\n \" role_assignments_path=ROLE_ASSIGNMENTS_PATH,\\n\",\n \" dataset_path=DATASET_PATH,\\n\",\n \" schema_dir=SCHEMA_DIR,\\n\",\n \" embed_model=EMBED_MODEL,\\n\",\n \" embed_backend=EMBED_BACKEND,\\n\",\n \" thresholds=QUALITY_THRESHOLDS\\n\",\n \" )\\n\",\n \" print(\\\"\\\\n✓ Quality evaluator initialized with custom thresholds\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"\\\\n Missing files - generate roles and dataset first\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 74,\n \"id\": \"8135e2e3\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[embedding_utils] Using OpenAI embeddings (text-embedding-3-small) for 11 texts\\n\",\n \"[embedding_utils] Using OpenAI embeddings (text-embedding-3-small) for 47 texts\\n\",\n \"Overall: 11 databases, 53 roles, 7252 entries\\n\",\n \"Pass Rate: 100.0% (11/11 pass)\\n\",\n \"\\n\",\n \"Using Thresholds: deny_rate_min=5.0%, max_overlap=80%, coverage_std_min=0.065\\n\",\n \"\\n\",\n \"=== Deny Rate Analysis ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseDeny%AllAllow%AllDenyRolesStatus
0california_schools73.5%1.1%05OK
1card_games46.9%2.1%05OK
2codebase_community37.8%0.0%05OK
3debit_card_specializing54.7%0.0%06OK
4european_football_257.1%1.6%05OK
5financial70.6%0.0%05OK
6formula_144.7%8.7%04OK
7student_club49.9%1.3%05OK
8superhero49.1%0.0%05OK
9thrombosis_prediction33.7%2.5%04OK
10toxicology47.4%11.7%04OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Deny% AllAllow% AllDeny Roles Status\\n\",\n \"0 california_schools 73.5% 1.1% 0 5 OK\\n\",\n \"1 card_games 46.9% 2.1% 0 5 OK\\n\",\n \"2 codebase_community 37.8% 0.0% 0 5 OK\\n\",\n \"3 debit_card_specializing 54.7% 0.0% 0 6 OK\\n\",\n \"4 european_football_2 57.1% 1.6% 0 5 OK\\n\",\n \"5 financial 70.6% 0.0% 0 5 OK\\n\",\n \"6 formula_1 44.7% 8.7% 0 4 OK\\n\",\n \"7 student_club 49.9% 1.3% 0 5 OK\\n\",\n \"8 superhero 49.1% 0.0% 0 5 OK\\n\",\n \"9 thrombosis_prediction 33.7% 2.5% 0 4 OK\\n\",\n \"10 toxicology 47.4% 11.7% 0 4 OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Semantic Quality (Similarity: role-schema alignment, Coverage: column access, Diversity: coverage std) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseSimilarityCoverageDiversityStatus
0california_schools0.690234.8%0.0996OK
1card_games0.684350.0%0.2965OK
2codebase_community0.633260.6%0.2888OK
3debit_card_specializing0.626463.8%0.1299OK
4european_football_20.679931.3%0.0984OK
5financial0.641046.8%0.1288OK
6formula_10.659944.0%0.1480OK
7student_club0.678050.5%0.1701OK
8superhero0.683561.3%0.1895OK
9thrombosis_prediction0.660769.3%0.3798OK
10toxicology0.669869.7%0.1134OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Similarity Coverage Diversity Status\\n\",\n \"0 california_schools 0.6902 34.8% 0.0996 OK\\n\",\n \"1 card_games 0.6843 50.0% 0.2965 OK\\n\",\n \"2 codebase_community 0.6332 60.6% 0.2888 OK\\n\",\n \"3 debit_card_specializing 0.6264 63.8% 0.1299 OK\\n\",\n \"4 european_football_2 0.6799 31.3% 0.0984 OK\\n\",\n \"5 financial 0.6410 46.8% 0.1288 OK\\n\",\n \"6 formula_1 0.6599 44.0% 0.1480 OK\\n\",\n \"7 student_club 0.6780 50.5% 0.1701 OK\\n\",\n \"8 superhero 0.6835 61.3% 0.1895 OK\\n\",\n \"9 thrombosis_prediction 0.6607 69.3% 0.3798 OK\\n\",\n \"10 toxicology 0.6698 69.7% 0.1134 OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Policy Overlap Analysis ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseAvgOverlapMaxOverlapStatus
0california_schools30.7%57.1%OK
1card_games11.9%23.8%OK
2codebase_community28.0%57.8%OK
3debit_card_specializing47.0%65.0%OK
4european_football_214.4%23.8%OK
5financial21.5%37.0%OK
6formula_129.3%32.9%OK
7student_club30.2%45.0%OK
8superhero33.0%52.6%OK
9thrombosis_prediction18.1%38.5%OK
10toxicology53.7%66.7%OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database AvgOverlap MaxOverlap Status\\n\",\n \"0 california_schools 30.7% 57.1% OK\\n\",\n \"1 card_games 11.9% 23.8% OK\\n\",\n \"2 codebase_community 28.0% 57.8% OK\\n\",\n \"3 debit_card_specializing 47.0% 65.0% OK\\n\",\n \"4 european_football_2 14.4% 23.8% OK\\n\",\n \"5 financial 21.5% 37.0% OK\\n\",\n \"6 formula_1 29.3% 32.9% OK\\n\",\n \"7 student_club 30.2% 45.0% OK\\n\",\n \"8 superhero 33.0% 52.6% OK\\n\",\n \"9 thrombosis_prediction 18.1% 38.5% OK\\n\",\n \"10 toxicology 53.7% 66.7% OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n }\n ],\n \"source\": [\n \"# 5.2 Run Quality Evaluations and Display as DataFrame\\n\",\n \"import pandas as pd\\n\",\n \"import importlib\\n\",\n \"\\n\",\n \"# Force reload modules to use latest code\\n\",\n \"import src.role_evaluator.quality_metrics\\n\",\n \"import src.role_evaluator.quality_visualizer\\n\",\n \"importlib.reload(src.role_evaluator.quality_metrics)\\n\",\n \"importlib.reload(src.role_evaluator.quality_visualizer)\\n\",\n \"\\n\",\n \"from src.role_evaluator.quality_metrics import print_quality_report\\n\",\n \"\\n\",\n \"# Set display options for full content (no truncation)\\n\",\n \"pd.set_option('display.max_colwidth', None)\\n\",\n \"pd.set_option('display.max_rows', None)\\n\",\n \"pd.set_option('display.width', None)\\n\",\n \"\\n\",\n \"if 'evaluator' in dir():\\n\",\n \" report = evaluator.evaluate_all()\\n\",\n \" \\n\",\n \" # Summary\\n\",\n \" print(f\\\"Overall: {report.total_databases} databases, {report.total_roles} roles, {report.total_entries} entries\\\")\\n\",\n \" print(f\\\"Pass Rate: {report.pass_rate:.1%} ({report.total_databases - len(report.databases_with_issues)}/{report.total_databases} pass)\\\")\\n\",\n \" print(f\\\"\\\\nUsing Thresholds: deny_rate_min={QUALITY_THRESHOLDS['deny_rate_min']}%, \\\"\\n\",\n \" f\\\"max_overlap={QUALITY_THRESHOLDS['max_overlap']:.0%}, \\\"\\n\",\n \" f\\\"coverage_std_min={QUALITY_THRESHOLDS['coverage_std_min']}\\\\n\\\")\\n\",\n \" \\n\",\n \" # Deny Rate DataFrame - Full display\\n\",\n \" if report.deny_rate_metrics:\\n\",\n \" deny_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"Deny%\\\": f\\\"{m.deny_rate:.1f}%\\\",\\n\",\n \" \\\"AllAllow%\\\": f\\\"{m.all_allow_pct:.1f}%\\\",\\n\",\n \" \\\"AllDeny\\\": m.all_deny_queries,\\n\",\n \" \\\"Roles\\\": len(m.roles),\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.deny_rate_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"=== Deny Rate Analysis ===\\\")\\n\",\n \" display(deny_df)\\n\",\n \"\\n\",\n \" # Semantic Quality DataFrame \\n\",\n \" if report.semantic_metrics:\\n\",\n \" sem_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"Similarity\\\": f\\\"{m.avg_similarity:.4f}\\\",\\n\",\n \" \\\"Coverage\\\": f\\\"{m.avg_coverage:.1%}\\\",\\n\",\n \" \\\"Diversity\\\": f\\\"{m.coverage_std:.4f}\\\",\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.semantic_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Semantic Quality (Similarity: role-schema alignment, Coverage: column access, Diversity: coverage std) ===\\\")\\n\",\n \" display(sem_df)\\n\",\n \"\\n\",\n \" # Policy Overlap DataFrame\\n\",\n \" if report.overlap_metrics:\\n\",\n \" ovl_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"AvgOverlap\\\": f\\\"{m.avg_overlap:.1%}\\\",\\n\",\n \" \\\"MaxOverlap\\\": f\\\"{m.max_overlap:.1%}\\\",\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.overlap_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Policy Overlap Analysis ===\\\")\\n\",\n \" display(ovl_df)\\n\",\n \"else:\\n\",\n \" print(\\\" Evaluator not initialized\\\")\\n\",\n \"\\n\",\n \"pd.reset_option('display.max_colwidth')\\n\",\n \"pd.reset_option('display.max_rows')\\n\",\n \"pd.reset_option('display.width')\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 75,\n \"id\": \"89f843e7\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# # 5.3 Quality Dashboard Visualization\\n\",\n \"# import matplotlib.pyplot as plt\\n\",\n \"# from src.role_evaluator.quality_visualizer import RoleQualityVisualizer\\n\",\n \"\\n\",\n \"# visualizer = RoleQualityVisualizer(evaluator=evaluator, report=report)\\n\",\n \"# fig = visualizer.plot_quality_dashboard()\\n\",\n \"# plt.show()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 76,\n \"id\": \"86eb26de\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Total roles: 53, SystemManager: 11\\n\"\n ]\n },\n {\n \"name\": \"stderr\",\n \"output_type\": \"stream\",\n \"text\": [\n \"/tmp/ipykernel_1782890/140258372.py:110: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.\\n\",\n \" plt.tight_layout(rect=[0,0,0.95,0.95])\\n\"\n ]\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Saved: /home/feiy/Role-SQL-benchmark/plot/column_level_rbac_semantic.png\\n\"\n ]\n },\n {\n \"data\": {\n \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAABtcAAAOzCAYAAADDRVknAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAXEgAAFxIBZ5/SUgABAABJREFUeJzs3XdYU9f/B/B3QtgblK1MweLAWdyg4t6tde9arbXVWq211jrraB1122pb96rWva3iFve2OBG3IsqQTXJ/f/AjX+O9gQCBgL5fz5NHc3LuuSfr5HI/93yOTBAEAURERERERERERERERESUK7mhO0BERERERERERERERERUUjC4RkRERERERERERERERKQjBteIiIiIiIiIiIiIiIiIdMTgGhEREREREREREREREZGOGFwjIiIiIiIiIiIiIiIi0hGDa0REREREREREREREREQ6Uhi6A0RERERERERERERUMgmCAEEQDN0NIqJ8k8lkkMlkedqGwTUiIiIiIiIiIiIi0plSqURsbCwSExORnp5u6O4QERWYiYkJrK2t4ejoCCMjo1zrywReVkBEREREREREREREOlAqlbh//z5SU1MN3RUiIr0zMzND2bJlcw2wceYaEREREREREREREekkNjYWqampMDIygrOzMywtLSGXyw3dLSKifFOpVEhKSsKzZ8+QmpqK2NhYODk55bgNg2tEREREREREREREpJPExEQAgLOzM2xtbQ3cGyKigpPL5erx7PHjx0hMTGRwjYiIiIiIiIiIiIgKThAE9RprlpaWhbafzLQ0XFi6BKpMJar3HwiFmVmh7YuIKFv2uJaeng5BECCTybTWZXCNiIiIiIiIiIiIiHIlCIL6/4WZCvL6xvU4MnkiAMDY3BzVPh1QaPsiIsr25riWW3CNyXCJiIiIiIiIiIiIqFhQZWbi9MJ56vsR82YjPem1AXtERCTG4BoRERERERERERERFQs3tm9B/P1omEAGC5kcKbEvcOGvPwzdLSIiDQyuEREREREREREREZHBCSoVTs2fAwDwMjZDORMLAMCZ3xYgNT7ekF0jItLA4BoRERERERERERERGdztvbsRe/MGFJDB09gMbkYmsJIZIS0hHmd/X2jo7hERqTG4RkREREREREREREQGJQgCTs2bDQDwNDaDsUwOmUwGfxNzAMD5P39H8osYA/YQ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3LkTW7Zswb59+9RrrQH5+w6sW7cOH374ISpWrKjTc9CFTBAEQW+tEREREREREREREdE7SaVS4caNGwCAgIAAUWq5/EhNTcWPP/6onh2kMjFBmp83Ml1dIBgbQ5aRAePHT2FyJysVJAA0atQIEydOLLQ1xyjL9OnTMXr0aNy9e1ed6o+oKIWEhOD69euIiYnJdxunT59GcHAwVq5ciR49euRYNy9jHINrRERERERERERERJSrwgiuAYBSqcT69euxbt06jTWu3ubu7o7OnTujS5cuets3aZeSkoJy5cqhffv2mD9/vqG7Q++wp0+fwsXFRaNs48aN+OSTT9C3b1/89ddf+W67Xbt2iIqKwsWLF3MdN/IyxjEtJBEREREREREREREZjJGREbp164bOnTvj5MmT2Lp1Kx49eoTk5GRYWFjA3d0d7dq1Q+3atYtsjTXKWgts+fLlOHv2LARBgEwmM3SX6B3Vs2dPJCQkoHr16rCwsMCVK1ewb98+ODo6Yty4cfluNy0tDdWrV8fo0aP1HpDnzDUiIiIiIiIiIiIiylVhzVwjovfbH3/8gSVLluDWrVtITExEqVKl0KRJE4wfPx4+Pj5F1g+mhSQiIiIiIiIiIiIivWJwjYjeZXkZ4zj6EREREREREREREREREemIwTUiIiIiIiIiIiIiIiIiHTG4RkRERERERERERES5kslk6v+rVCoD9oSISP/eHNfeHO+kMLhGRERERERERERERLmSyWQwMTEBACQlJRm4N0RE+pU9rpmYmOQaXFMURYeIiIiIiIiIiIiIqOSztrZGbGwsnj17BgCwtLSEXM45HERUcqlUKiQlJanHNWtr61y3kQmCIBR2x4iIiIiIiIiIiIio5FMqlbh//z5SU1MN3RUiIr0zMzND2bJlYWRklGM9BteIiIiIiIiIiIiISGdKpRKxsbFITExEenq6obtDRFRgJiYmsLa2hqOjY66BNYDBNSIiIiIiIiIiIiLKJ0EQwFPMRFSSyWSyXNdYE23D4BoRERERERERERERERGRbrjSJBEREREREREREREREZGOGFwjIiIiIiIiIiIiIiIi0hGDa0REREREREREREREREQ6YnCNiIiIiIiIiIiIiIiISEcMrhERERERERERERERERHpiME1IiIiIiIiIiIiIiIiIh0xuEZERERERERERERERESkIwbXiIiIiIiIiIiIiIiIiHTE4BoRERERERERERERERGRjhhcIyIiIiIiIiIiIiIiItIRg2tEREREREREREREREREOmJwjYiIiIiIiIiIiIiIiEhHDK4RERERERERERERERER6YjBNSIiIiIiIiIiIiIiIiIdMbhGREREREREREREREREpCMG14iIiIiIiIiIiIiIiIh0xOAaERERERERERERERERkY4YXCMiIiIiIiIiIiIiIiLSEYNrRERERERERERERERERDpicI2IiIiIiIiIiIiIiIhIRwyuEREREREREREREREREemIwTUiIiIiIiIiIiIiIiIiHTG4RkRERERERERERERERKQjBteIiIiIiIiIiIiIiIiIdMTgGhEREREREREREREREZGOGFwjIiIiIiIiIiIiIiIi0hGDa0REREREREREREREREQ6YnCNiIiIiIiIiIiIiIiISEcMrhERERERERERERERERHpiME1IiIiIiIiIiIiIiIiIh0xuEZERERERERERERERESkIwbXiIiIiIiIiIiIiIiIiHTE4BoRERERERERERERERGRjhhcIyIiIiIiIiIiIiIiItIRg2tEREREREREREREREREOmJwjYiIiIiIiIiIiIiIiEhHDK4RERERERERERERERER6YjBNSIiIiIiIiIiIiIiIiIdMbhGREREREREREREREREpCMG14iIiIiIiIiIiIiIiIh0xOAaERERERERERERERERkY4YXCMiIiIiIiIiIiIiIiLSEYNrRERERERERERERERERDpicI2IiIiIiIiIiIiIiIhIRwyuEREREREREREREREREemIwTUiIiIiIiIiIiIiIiIiHSkM3QEiorxwcXFBUlISypYta+iuEBERERERERERFYn79+/D0tIST58+LXBbbdu2xZ07d/TQK/3z9fXFtm3bDN0NolwxuEZEJUpSUhIyMjIM3Q0iIiIiIiIiIqIik5GRgaSkJL20defOHdy+/R/8vIz10p6+3L7Hc35UcjC4RkQlSvaMtWvXrhm4J4UjMzMTCgWHZiLSH44rRKRvHFeISJ84phCRvr2r40qFChX02p6flzGuHPbUa5sFVSkk2tBdINIZ11wjIiomBEFAdHQ0BEEwdFeI6B3BcYWI9I3jChHpE8cUItI3jitEVFTevRA+EVEJJZPJ4Ovra+huENE7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qv92yAKAVRRteRWu80JaSREKzp3Dho8+RK+H/sb33g343mPuAXzvVacx771dB/bCOqgFyv77ne96Go0GWk3Fn05mi6XKCUvVrWcym2u8NplWq4Xmv7+L+q5nNJlsvzMx0h+bN2xH7249APC9Vx1Xeu8x9/5H6vfe8dPH4Ne+YnvlBgPEGtqj9Pr/nThpMFS/TwECPPT/nUZRFGEor5oVQMVsKR4e+v+uZkV5eXm166kEFXT/PfFStFpRbrRfTx8iYPf+nejcqYvk771Lly7Bq5kVFosFJmP1eabWaKDV/jf3zBaYa8k9TeV6pprzTKPVQqP5b+6ZzLDYrWcA/vtyanVaW16YTCZYzPZ5ofEtw759+9CqVStFv/eYe1Ux9/jeq89779iRveh/7/+y2mq11vhcVSo1dDrtf+uzwmT633oawYDK+FWr1dBqK9er+XucWn1D7plryb3K74W1fI/TaOxzr0VzC37bkoxjxwbYrdeQ954jWEVln1hGpGScFpIU7fovW2+++SZ27tyJlStX4sCBA8jNzUVycjL+9re/OWTfb775Jo4cOYItW7Zg9+7ddh1nixYtsg22rV69Grt27bIt+7//+z+kpKRg1apVtqkYK3322We1zq8cFxeHY8eOYfv27di8eXONF6vX6XTYtm0btm/fjj///BMjR460LcvIyLCb5vHVV1+1HaiOjo5GWloaNm7ciPXr1+P48ePw9fUFUPFl+Z133qn1NXnjjTeQlpaG33//Hampqbjnnntw9OhR/PTTT7Z1EhIScPLkSaxfvx6pqal2029evHix1sHFm50oiigoKOA0S+Q2LCaTrWstxtMX6gZOeq8WBMR4+gBmEzJ+/jcsJl57raGYK0T1U15ejrz8a1D5e8ldSr2o/L2QX1hQ48EhR2KukCu5dPkivJu51vXWKnkFeeDqteoHAZrKaDRC0FY94UkWIqC71rpe00ICgEor1nggm4hcm9VqRW7uZUSEN+1wtSgC5y53VNy0kBHNVci9cqXay8YQkWsSRP5VRAo2fvx4W8dUYmIinnjiCSQmJqJt27a2M5muFx0dbTtLatCgQdi6davd8usvvP7AAw/YXTPs+sf6+/vj0qVLdgNq9957r901zXbt2oW+ffvisccewyeffGJXs+66qcsuXrxoN/j2r3/9C1OnTgVQcc21r776yrbshx9+wF/+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K6+EKIrQ6/W45JJL0LdvX0RHR6OmpgZpaWm2ebWaK05YrVZceumlGD58OPR6PXbv3t0gvtaqP77xhRdeiAEDBkAul+OOO+7A5MmTW70uuVyOefPm4Z577rE99sgjj+Ddd99F7969UVlZid27d2PChAm4+uqrAQBDhw7Fjh07AAApKSno1asX4uLisG/fPuTn57d620258MILMXToUNtndPjwYSQkJGDQoEFITU21K0p2xKJFi/DII48gODgYvXv3hr+/P8rKyuzmXgOaH0969uzZWLZsGQIDA5GSkmI3t999991nK4xdeeWVuOCCC/DHH38AAFauXIlu3bph4MCB8Pb2xpkzZ3Do0CG71wNAYGAgnnjiCbzyyisAaq9qmTp1KhITExEfH4/CwkLs3bsXDzzwACZMmNDie+7s766+++67z26ewrCwMLz//vt4//337ZabNm0apk2bJvn261xwwQUYOXKkrXPv0KFD6NmzJwYOHIgjR440mJPtfNdc1xqAdp2cjdR4IbO6wta91qcVc68R0flBEIRWzwXhbOFdu0L9R+cPE6iOiYHqrwPQV9dA1LV/btJzCVax4VxYErNWVsOnsAQXdXCOWFcRHByMfvEJ2JN5Gur4CGeHYyNXKBDo74+CshIIfroWlxdyCqEJ9YOiFctKRbSKMG9KxaO33mU3jLdMJkNkRCTOFlRA3dWvmTV0kABkaytbXq6VjAUV6BbZrU1DYxOR53CnYxUicg/MK0TkKJL8gpk0aRIefPBBu8d2796N3377DRqNBldeeWWjr5s8eTI+/PBDu5MRhw4dwurVq7Fp0yZbYQ1ofr6nq666ClqtFjt27GhQWJs5c2aDzqbmTJ061a57LTs7Gz/99BOWL1+O48ePt3o9de6++27MmTPH7sdi3XCBv/32W4N55F5++WW7Lru0tDSsXbsW+fn5eOmll9q8/cZ89dVXdpNyFhYWYuPGjThx4gRuueUWSbZRp6CgANu3b8dPP/2ErVu32hW4pk+fjsGDBzf6uqFDh2L48OE4ePAgtm7davc5DRs2zK7YKggCVq5cabeu0tJSbN26FatXr8bu3btt263/o33u3Ll2xU+gdljDX375BSkpKXbdaC1xxHd3rrqOwzrZ2dlYvnx5g1v9oT87w5dffmk3gWtBQQE2btyI3Nxc3HfffXbLqlSqTo/HVbXUtQa0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ykrmzZvH+PHj693u2Vx++eWO/7fb7dx8883k5eU5nlNVle+//97xtzwzptdee82xvN1u5/HHH3d6/fR9qLWJiYlx/P/q1av5/fffAdi1axcvvviiR2Ly8/Nzenzs2LF6lx0xYgS9evVyPN64caPj/2+55RbXB+djFEWhY8eOLikiuLJrrYZ0rwlPyMvLw2b0O/eCXsxm9HP6nnMnV+YVIcQfdDodit27TvwVmx2druVH/feVvLLnwF5Msa45RqqPoii069+R4i2FLbqdWtvVa6h0YXGtYEseV4yd1Or/5sI7+UpOEUJ4D8krQgh38ao51wCefPJJ5s+fT2Vl9d19X375JYsWLaJPnz7odDq2bNmCxWLhhhtuYMKECfTr148tW7YAsGrVKlJSUujVqxd79+51mrOsW7duXHPNNUD18HS33347r7zyClBdLBo8eDCDBg2ioKCA7du31xtfVFQU9957r+O96enppKSkMGDAAKKioigoKGD37t2OrqPrrruu3nUdPXqUHj16MGDAAA4ePEh6errjteDgYG699Vageo4xPz8/KioqAHj55ZdZvXo1AQEBrF271vF8XWbNmsW9995LVFQU3bp1IywsjKKiolpdUDVzM0yYMIGBAwc6ioI//PADHTt2pG/fvgQGBpKTk8OuXbscf5+meOCBB/jkk08c844tW7aM5ORk+vTpQ2BgIDt27CA7O5uCggL8/f3p3bs3kydP5ocffgBg//79pKam0r9/fw4ePMiBAwcc627Xrh133HFHk2PztJEjR/L5558D1XPnde/endjYWLKysjx2x82Z83YMHTqUPn36oNVqufnmm52KpQB33303//d//+f0XHx8PKNGjWrxWH2BN3at1ZC514QnmM1mVBftw56iajQeGxYSXJNXhBDOAgICUCot517QjZQqq9vmF/GFvHIg8wDBAzu2+HYi+7bn+L8OYr8oCo2h5YdqB9DoNFSVuqa4ZquyUrm/nIvuvMgl6xOiLr6QU4QQ3kXyihDCHbzualXPnj357rvvnOapOnXqFL/88guLFy92uvNbo9Ewd+5cevbs6Xju+PHjLF682Kmw1rlzZ3766SenIfeefvppLrjgAsfjiooKVqxYwfbt2+nZsye9e/euN8aZM2fy5z//2fHYarWybt06fvrpJ1avXu00nN/Z5rq68cYbKSoqYunSpU6FNY1Gw4cffkh0dDRQPQnnE0884fTedevWsWzZMnQ6HQ8++GC926hx8uRJfv31V+bOncuKFSucimPXXXcd/fr1A6rv7vjhhx8cjwEKCwtZsWIF8+bNY9OmTY73njm3WEPFxMSwYMEC2rdv73iuuLiYVatW8fPPPzu6+U43e/ZsRowY4Xicn5/PkiVLnApr0dHRzJs3r1UPV/LII484dYpZrVaOHj2Kqqr85S9/8UhMV111lVNMhw4dYu7cuXz//fdOv/8aU6dOrfU3mDZtWpP3l7ZEVVWOHTvW7IPAluhaqyHda8LdrFYrdlr3HYd2lFpd6O7iqrwihHDWsWNHrHnFXvNvS1VVbHkljmHlW3pbrT2vlJaWUlZVjr4F51urofPTE9o5ipLddY+M0hIUrYJdtWO325u9rrydJxnaf4jbCrei7fGFnCKE8C6SVxpJ9bIfIVoRr7zaPX78ePbt28fjjz9O//79CQkJQafTER0dzfDhw5k+fbpj2bi4ODZu3Mg777zDyJEjCQ8PR6fTERYWxtChQ3nttdfYunUrycnJTtvw9/dn+fLlPPLIIyQkJGAwGEhISOCBBx5gzZo1Z50bSqvV8umnn/LLL79www030KlTJ/z8/NDr9cTExDBixAgef/xxtm3bxvDhw+tdz6233sqSJUu46KKLCAoKIiAggIsuuojly5c7uuxqPProo/z73/+mR48e6PV6IiIimDJlCps2baJbt271buPNN9/kH//4B0OHDqVjx45OcY4ePZpPPvmEL7/80uk9sbGxrFu3jtmzZ3PZZZcRExODXq/HZDKRmJjI+PHjef311zly5Ei92z2XgQMHsmfPHl566SWGDRvm+LtFRkZywQUX8NhjjzkNfxkcHMwvv/zC559/ztixY2nXrh06nY6goCD69+/P008/zZ49e5wKpq1Rt27dWLlyJZdccgkBAQEEBAQwfPhwFixYwKOPPuqRmOLj41m8eDGjRo0iODj4nMv7+fk5ui6humB78803t2SIPkNRFBITE5s1dEFLda3VkLnXhLvpdDo0rfwIW4PqdIOPO7kirwghajOZTESEhGErLvd0KADYisoJDwnDaGz5YpEv5JUjR45gjPZ32/baXdCRks2FqG4cSlSja37XtGpXKdtSxISxTZsOQIiG8IWcIoTwLpJXhBDuoqhSxhdCuNitt97Kxx9/DMDF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9OhRjh49yty5c7n33nt544033BG6wz/+8Q+nImCN/fv3s3//fv7973/zwQcf1CrInW7Lli289tpr5zzRq6ysZPTo0axcudLxXFVVFZ999hmbN29my5YtmEymBsX96aef8uWXX9Z6vuZ3v3jxYubOnct3332HRtP4WvKyZcsYN24cFovF6fns7Gyys7NZv349e/bsYfTo0Y7XKioquOGGG5g7d67TeyorKykpKeHAgQP06tWL3r1717nNr776io8//hibzeZ4bt26dYwbN46lS5dy0UUXOS3f1L/dqlWruPLKKzl16pTT88ePH2f+/PnMnz+fCRMm8N1332E0Nuzg/9Zbb3UUVGsUFxdTXFxMRkYGCxYsIDExkRtvvLFB62trVFUlMzOTpKQkOQgUQriE5JXWrbFdazWke020JF/NKwcPHsQU4+/pMBrEFOvPwYMH6dmzp6dD8YiKigpWb1jJoPujPR2Kk7h+Iax+YwU33Xgzfn5+ng6n1WhOTjkvpTsrdi1t1vYNBgOVpe677/xUNiQkNOw7Of+YkWEjk1o4IiF8j68eqwghvI8U15pp9+7dTJkyhYqKCsdzERER9O7dG61Wy+bNm52GZQTw9/enS5cuhIeHExAQQH5+Plu3bqWsrAyoLsBdd911DBo0qFmxTZkyhfLychYuXOh4rmvXrnTr1g2AAQMGAPDOO+84FWcMBgMDBw6ksrKSzZs3o6oqZrOZ2267jc6dOzN06NA6tzd/fvVdeklJSaSmppKRkVHncrm5ueTm5hIfH0/nzp1Zv36947Pv3buXr7/++qxFvDMZDAa6du1KREQEQUFBFBcXs23bNgoLCwH473//y7fffst1113X4HXWeOmllxyFNa1Wy6BBgwgPD+fYsWMcPHiwzkmr//rXvzoV1hRFoWfPnsTHx3P06FF27tx51m1++OGHBAQEcMEFF3Dw4EEOHToEgM1m45lnnnEqrjX1b5ednc2kSZMcvyOA1NRUOnbsyMaNGykuLgZg3rx53Hfffbz33nvn/F1lZWU5FdYiIyMZMGAANpuNI0eOkJmZidnc8LsK65tfLyMjg7i4OHbt2lXrNa1W69i/bTYbe/furXMdBoOB1NRUAMxmc73dfX5+fqSkpADVJ/Hp6el1LhcQEEBSUvVJT2lpKQcPHqxzueDgYBISEoDqouPhw4drLWO328nOziYu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CxYs0L59++zL8fHx9rhd7eKhNi6c0+udd95xiPtqvffee/r+++9VWvrbF21/f3/dcMMNGjZsmEO7smET+/bt67B++vTpWr9+vcO6gwcPmlJ0q8rfrk+fPvb1BQUFDsXC48eP680337Qve3t7q3v37leMJzc3V9OnT1dKSop9XVhYmOLj43XbbbfZ1+Xn5yszM9PZ06xTLBaLGjZsyNAFAExDXql9zOy1VobeazCTp+aVa5tfq6LM2lEQKczMV2zza10dhkuUlJTIy+re157FamEo/EowI6f4+vpq7KNPa+NSQ0WFV/dDzuCgYJUWWVVUZO4PQYsLDW1aalHvP4bK6nPlczyWUqistDD16N7L1DiAusRT71WqhSHJZrjXiw6HqEUorlXRpEmTHIpNCxcuVIsWLdS9e3f17t1bjRs31qOPPipJ6ty5s71dfn6+rr/+evXv319t27bVlClTXJL0rVarnn/+eftyYWGhunbtqvj4eN16660aOXKkfZuXl5cmTZpU4zFeyoWfpyR16dJF/fr1080336y//OUvpnyey5Yt05133qnw8HDddtttGjhwoHr16qUOHTo4tGvZsqUklSu8nT17VgkJCWrfvr3uvvtudezYUa1bt9bWrVurHFtV/nZ//etfFRISYl9+5ZVXdP3116tnz56Ki4vTsWPH7NseeughtWjR4orxFBQUaMKECWrZsqViY2PVs2dP3XPPPbr11lv1j3/8w96uQYMGpvUq9DSGYSgjI4OhCwCYhrxSu5jda60MvddgJk/NK7ExsbL9WjsKIsbJEsVeG3vlhh7IarXKVo1D95nBKDFktVpdHUatYVZOad26tW6/9S79+OXVFcktXhaFhUXofI6503T89KWhVjcGqum1V54nsLjIprVLLBo7ZoLb/KgZqI089V4FgPuhuFZF7dq105IlS1S/fn37uuzsbH333Xf65ptvlJWVZV8/duxYNW3a1L588uRJffnll9q3b5/+/Oc/Oz30ntnGjRunxx9/3L5cWFio9evX66effrL/j8jHx0dvv/22unXr5pIYKzJs2DDdeOON9uWzZ8/qq6++0q5du9SrVy917drVtGPl5ORo06ZN+uyzz/Ttt986zLHWrVs3DRgwwL48b9489e/f375sGIZ2796tL774Qjt27DB1SMSr/dtFRUVpxYoVDvOi7dmzR6tXr9aZ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y7WZO3euQ5sZM2aUa5Obm+vQ5r333ivX5nLi4+Md2j744IMO23v06OGw3cfHx9i6dWuF+zp9+rRzH8j/Wrx4scO+R48efcm2eXl5RnFxcaViT01NLfdZ3HzzzYbNZrO3ef3118u1GThwoMN+xo8fX+66vdjF19rkyZMdtq9du7bccVJTU537oP7X1V5HTz755CX36UxclY194sSJDm379u3rsL1Dhw4O2z/88MNKfQ4AAABAbUbPNQAAAADldOnSRT/++KN69eoli8Vy2bZZWVl64IEHtGzZMof169atc1j++eef5e3tLYvFYn9ZrVYdPnzYod369esve7xevXqpYcOG9uWYmJhybYYMGSI/Pz/7cqtWrcq1qaiHXEpKiiZOnKhu3bqpcePGCggIsMfaqVOncu2PHTt22ViDgoI0YsQIh3Vt2rRxKhaz2Gy2cp/poEGDKjwfSZXuudahQweHa2TevHnq1auXJkyYoHfffVebN2+2DwsaEBAgq7XqU3/ff//9Dses6BoYPny4w/LF10B1fuZmX0c+Pj5VGsr0aowZM8bhb7Vq1SodPXpUknTw4EHt2LHDvq1+/foaNGhQjcYHAAAAuBLFNQAAAAAViouL06pVq3To0CG99dZbGjZsmFq2bHnJ9pMnT3ZYPn78+FUdNz09/bLbLx56rl69euXaXFxsCQgIKNembKi9MvPmzVObNm00bdo0bdy4URkZGSooKLhsLLm5uZfdHh0d7VDkczYWM2VnZ6uwsNBhXceOHU3bf8uWLR3m6LLZbPr22281ffp0jRo1Sl27dlWDBg3Uo0cPrVmzxpRjmnENXDyHmFmq4zqKiopSWFiYmWFeUdOmTXXvvffal202m31+uIuHhBw6dGiF1zUAAADgqSiuAQAAALis6OhojR49Wh9++KEOHDig9PR0vfbaa+UepicnJ+vs2bNVPl5+fv5lt1/cs8rLq/zXmsr2vvrll1/06KOPVrrIZRjGZbdXVBDx9vau1DFqg9mzZ2v58uXq27dvhfOqFRcXa82aNerZs2e5Ho5XozquATNU13XUpEmTqoR11caNG+ew/O6778pms2nx4sUO60eNGlWTYQEAAAAuV/XxOAAAAADUKZGRkRo/frwyMjI0ffp0h23nz59XSEiIpN8KAnv27LFv69Gjh+bNm3fF/V/c06smLFmyxKEnk5eXl55+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\",\n \"text/plain\": [\n \"\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n }\n ],\n \"source\": [\n \"# 5.4 Semantic Alignment Visualization (Column-Level RBAC)\\n\",\n \"# Circle size = column coverage, Red triangles = SystemManager\\n\",\n \"import random\\n\",\n \"import math\\n\",\n \"import matplotlib.pyplot as plt\\n\",\n \"from matplotlib.colors import PowerNorm\\n\",\n \"from matplotlib import colormaps as cm\\n\",\n \"from collections import defaultdict\\n\",\n \"from matplotlib.lines import Line2D\\n\",\n \"import numpy as np\\n\",\n \"\\n\",\n \"sys.path.insert(0, str(project_root / \\\"plot\\\"))\\n\",\n \"from embedding_utils import cosine_similarity\\n\",\n \"\\n\",\n \"# Prepare records (recompute)\\n\",\n \"role_records = evaluator._prepare_role_records()\\n\",\n \"evaluator._compute_embeddings()\\n\",\n \"\\n\",\n \"# Build vis_records with is_system_manager\\n\",\n \"vis_records = []\\n\",\n \"for spec in role_records:\\n\",\n \" schema_emb = evaluator._schema_emb_dict.get(spec[\\\"schema_text\\\"])\\n\",\n \" role_emb = evaluator._role_emb_dict.get(spec[\\\"role_text\\\"])\\n\",\n \" \\n\",\n \" if schema_emb is not None and role_emb is not None:\\n\",\n \" raw_sim = cosine_similarity(role_emb, schema_emb)\\n\",\n \" similarity = max(0.0, min(1.0, (raw_sim + 1.0) / 2.0))\\n\",\n \" else:\\n\",\n \" similarity = 0.5\\n\",\n \" \\n\",\n \" total_cols = spec.get(\\\"total_columns\\\", 1)\\n\",\n \" accessible_cols = spec.get(\\\"accessible_columns\\\", 0)\\n\",\n \" col_coverage = accessible_cols / total_cols if total_cols > 0 else 0\\n\",\n \" \\n\",\n \" vis_records.append({\\n\",\n \" \\\"db_id\\\": spec[\\\"db_id\\\"],\\n\",\n \" \\\"role\\\": spec[\\\"role\\\"],\\n\",\n \" \\\"similarity\\\": similarity,\\n\",\n \" \\\"is_system_manager\\\": spec.get(\\\"is_system_manager\\\", False),\\n\",\n \" \\\"column_coverage\\\": col_coverage,\\n\",\n \" })\\n\",\n \"\\n\",\n \"sm_count = sum(1 for r in vis_records if r[\\\"is_system_manager\\\"])\\n\",\n \"print(f\\\"Total roles: {len(vis_records)}, SystemManager: {sm_count}\\\")\\n\",\n \"\\n\",\n \"# Plot function\\n\",\n \"def plot_semantic(records, output_path, title, dbs_per_panel=12):\\n\",\n \" db_to_entries = defaultdict(list)\\n\",\n \" sims = []\\n\",\n \" for rec in records:\\n\",\n \" sims.append(rec[\\\"similarity\\\"])\\n\",\n \" size = 90.0 + rec[\\\"column_coverage\\\"] * 220.0\\n\",\n \" db_to_entries[rec[\\\"db_id\\\"]].append({\\n\",\n \" \\\"sim\\\": rec[\\\"similarity\\\"], \\\"size\\\": size,\\n\",\n \" \\\"is_sm\\\": rec[\\\"is_system_manager\\\"],\\n\",\n \" })\\n\",\n \" \\n\",\n \" db_ids = sorted(db_to_entries.keys())\\n\",\n \" panels = [db_ids[i:i+dbs_per_panel] for i in range(0, len(db_ids), dbs_per_panel)]\\n\",\n \" \\n\",\n \" min_s, max_s = min(sims), max(sims)\\n\",\n \" if math.isclose(min_s, max_s): max_s = min_s + 1e-6\\n\",\n \" span = max_s - min_s\\n\",\n \" norm = PowerNorm(gamma=0.55, vmin=min_s, vmax=max_s)\\n\",\n \" cmap = cm[\\\"viridis\\\"]\\n\",\n \" \\n\",\n \" fig = plt.figure(figsize=(11, sum(0.35*len(p)+0.6 for p in panels)+2))\\n\",\n \" gs = fig.add_gridspec(len(panels), 1, height_ratios=[0.35*len(p)+0.6 for p in panels], hspace=0.18)\\n\",\n \" axes = []\\n\",\n \" \\n\",\n \" random.seed(42)\\n\",\n \" sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)\\n\",\n \" sm.set_array([])\\n\",\n \" \\n\",\n \" for pi, chunk in enumerate(panels):\\n\",\n \" ax = fig.add_subplot(gs[pi, 0])\\n\",\n \" axes.append(ax)\\n\",\n \" for ri, db in enumerate(chunk):\\n\",\n \" y = float(ri)\\n\",\n \" ax.axhline(y, color=\\\"#d0d0d0\\\", linestyle=\\\"--\\\", lw=0.9, zorder=0)\\n\",\n \" for e in db_to_entries[db]:\\n\",\n \" x = (e[\\\"sim\\\"] - min_s) / span + random.uniform(-0.012, 0.012)\\n\",\n \" if e[\\\"is_sm\\\"]:\\n\",\n \" ax.scatter(x, y, s=250, c=\\\"#d62728\\\", alpha=0.95,\\n\",\n \" edgecolors=\\\"#8c1c15\\\", lw=1.0, marker=\\\"^\\\", zorder=4)\\n\",\n \" else:\\n\",\n \" ax.scatter(x, y + random.uniform(-0.16, 0.16), s=e[\\\"size\\\"]*2.5,\\n\",\n \" c=[e[\\\"sim\\\"]], cmap=cmap, norm=norm, alpha=0.82,\\n\",\n \" edgecolors=\\\"#333\\\", lw=0.45, marker=\\\"o\\\")\\n\",\n \" ax.set_yticks(range(len(chunk)))\\n\",\n \" ax.set_yticklabels(chunk, fontsize=10, weight='bold')\\n\",\n \" ax.set_xlim(-0.05, 1.05)\\n\",\n \" ax.set_ylim(-0.6, len(chunk)-0.4)\\n\",\n \" ax.set_xticks(np.linspace(0, 1, 5))\\n\",\n \" ax.set_xticklabels([f\\\"{min_s + p*span:.2f}\\\" for p in np.linspace(0,1,5)], fontsize=9)\\n\",\n \" ax.grid(axis=\\\"x\\\", ls=\\\":\\\", lw=0.5, alpha=0.45)\\n\",\n \" \\n\",\n \" axes[-1].set_xlabel(\\\"Semantic similarity\\\", fontsize=12, weight='bold')\\n\",\n \" fig.suptitle(f\\\"{title}: Role-Schema Alignment\\\", fontsize=14, y=0.98, weight='bold')\\n\",\n \" cbar = fig.colorbar(sm, ax=axes, fraction=0.03, pad=0.015)\\n\",\n \" cbar.set_label(\\\"Similarity\\\", fontsize=10)\\n\",\n \" \\n\",\n \" legend = [\\n\",\n \" Line2D([0],[0], marker='^', color='w', markerfacecolor='#d62728',\\n\",\n \" markeredgecolor='#8c1c15', markersize=12, label='SystemManager'),\\n\",\n \" Line2D([0],[0], marker='o', color='w', markerfacecolor='#21918c',\\n\",\n \" markeredgecolor='#333', markersize=8, label='Other (size=col coverage)'),\\n\",\n \" ]\\n\",\n \" fig.legend(handles=legend, loc='upper right', fontsize=9)\\n\",\n \" plt.tight_layout(rect=[0,0,0.95,0.95])\\n\",\n \" fig.savefig(output_path, dpi=150, bbox_inches='tight')\\n\",\n \" plt.close(fig)\\n\",\n \" print(f\\\"Saved: {output_path}\\\")\\n\",\n \"\\n\",\n \"output_path = project_root / \\\"plot\\\" / \\\"column_level_rbac_semantic.png\\\"\\n\",\n \"plot_semantic(vis_records, output_path, \\\"Column-Level RBAC (BIRD)\\\")\\n\",\n \"from IPython.display import Image, display\\n\",\n \"display(Image(filename=str(output_path)))\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 13,\n \"id\": \"2dd807b4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Databases Requiring Review (1/11) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseDeny%AllAllow%CoverageCovStdMaxOverlapIssues
0california_schools63.1%5.6%50.8%0.05972.3%all-deny queries found (1) - SystemManager coverage broken; Low role diversity
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Deny% AllAllow% Coverage CovStd MaxOverlap \\\\\\n\",\n \"0 california_schools 63.1% 5.6% 50.8% 0.059 72.3% \\n\",\n \"\\n\",\n \" Issues \\n\",\n \"0 all-deny queries found (1) - SystemManager coverage broken; Low role diversity \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"Issue Thresholds:\\n\",\n \" - Deny% < 5%: roles too permissive\\n\",\n \" - Coverage > 85%: most roles have near-full access\\n\",\n \" - CovStd < 0.065: roles have similar coverage (low diversity)\\n\",\n \" - MaxOverlap >80%: redundant roles with similar policies\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 5.5 Export Problematic Databases as DataFrame\\n\",\n \"if report.databases_with_issues:\\n\",\n \" issues_data = []\\n\",\n \" for db_id in report.databases_with_issues:\\n\",\n \" row = {\\\"Database\\\": db_id}\\n\",\n \" \\n\",\n \" if db_id in report.deny_rate_metrics:\\n\",\n \" m = report.deny_rate_metrics[db_id]\\n\",\n \" row[\\\"Deny%\\\"] = f\\\"{m.deny_rate:.1f}%\\\"\\n\",\n \" row[\\\"AllAllow%\\\"] = f\\\"{m.all_allow_pct:.1f}%\\\"\\n\",\n \" \\n\",\n \" if db_id in report.semantic_metrics:\\n\",\n \" m = report.semantic_metrics[db_id]\\n\",\n \" row[\\\"Coverage\\\"] = f\\\"{m.avg_coverage:.1%}\\\" # Source of \\\"Most roles too permissive\\\" (>90%)\\n\",\n \" row[\\\"CovStd\\\"] = f\\\"{m.coverage_std:.3f}\\\" # Source of \\\"Low role diversity\\\" (<0.1)\\n\",\n \" \\n\",\n \" if db_id in report.overlap_metrics:\\n\",\n \" m = report.overlap_metrics[db_id]\\n\",\n \" row[\\\"MaxOverlap\\\"] = f\\\"{m.max_overlap:.1%}\\\" # Source of \\\"High max overlap\\\" (>70%)\\n\",\n \" \\n\",\n \" row[\\\"Issues\\\"] = \\\"; \\\".join(report.all_issues.get(db_id, []))\\n\",\n \" issues_data.append(row)\\n\",\n \" \\n\",\n \" issues_df = pd.DataFrame(issues_data)\\n\",\n \" print(f\\\"=== Databases Requiring Review ({len(issues_df)}/{report.total_databases}) ===\\\")\\n\",\n \" \\n\",\n \" # Display with full column width for Issues column\\n\",\n \" pd.set_option('display.max_colwidth', None)\\n\",\n \" pd.set_option('display.max_rows', None)\\n\",\n \" display(issues_df)\\n\",\n \" pd.reset_option('display.max_colwidth')\\n\",\n \" pd.reset_option('display.max_rows')\\n\",\n \" \\n\",\n \" print(\\\"\\\\nIssue Thresholds:\\\")\\n\",\n \" print(\\\" - Deny% < 5%: roles too permissive\\\")\\n\",\n \" print(\\\" - Coverage > 85%: most roles have near-full access\\\")\\n\",\n \" print(\\\" - CovStd < 0.065: roles have similar coverage (low diversity)\\\")\\n\",\n \" print(\\\" - MaxOverlap >80%: redundant roles with similar policies\\\")\\n\",\n \"\\n\",\n \"else:\\n\",\n \" print(\\\"[OK] All databases pass quality checks!\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"7586c455\",\n \"metadata\": {},\n \"source\": [\n \"## 6. Regenerate Roles for Problematic Databases\\n\",\n \"\\n\",\n \"Human-in-the-loop workflow for fixing quality issues:\\n\",\n \"\\n\",\n \"| Step | Cell | Description |\\n\",\n \"|------|------|-------------|\\n\",\n \"| 1 | 6.1 | Select database, view schema and current roles |\\n\",\n \"| 2 | 6.2 | Write regeneration hints (edit manually) |\\n\",\n \"| 3 | 6.3 | Execute regeneration with LLM |\\n\",\n \"| 4 | 6.4 | Preview and compare OLD vs NEW |\\n\",\n \"| 5 | 6.4.1 | Select & combine roles from OLD and NEW |\\n\",\n \"| 6 | 6.5 | Apply changes if satisfied |\\n\",\n \"| 7 | 6.6 | Regenerate RBAC Dataset with updated roles |\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 32,\n \"id\": \"70f25858\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"Database: formula_1\\n\",\n \"======================================================================\\n\",\n \"\\n\",\n \"=== Schema (13 tables, 94 columns) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
TableColumnTypePKFK
0circuitscircuitIdINTEGERYes
1circuitscircuitRefTEXT
2circuitsnameTEXT
3circuitslocationTEXT
4circuitscountryTEXT
..................
89resultsfastestLapINTEGER
90resultsrankINTEGER
91resultsfastestLapTimeTEXT
92resultsfastestLapSpeedTEXT
93resultsstatusIdINTEGERstatus.statusId
\\n\",\n \"

94 rows × 5 columns

\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Table Column Type PK FK\\n\",\n \"0 circuits circuitId INTEGER Yes \\n\",\n \"1 circuits circuitRef TEXT \\n\",\n \"2 circuits name TEXT \\n\",\n \"3 circuits location TEXT \\n\",\n \"4 circuits country TEXT \\n\",\n \".. ... ... ... ... ...\\n\",\n \"89 results fastestLap INTEGER \\n\",\n \"90 results rank INTEGER \\n\",\n \"91 results fastestLapTime TEXT \\n\",\n \"92 results fastestLapSpeed TEXT \\n\",\n \"93 results statusId INTEGER status.statusId\\n\",\n \"\\n\",\n \"[94 rows x 5 columns]\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Current Roles (5) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
RoleDescriptionTablesColumnsPolicy
0RaceAnalystAnalyzes race performance data including lap times, pit stops, and qualifying results965 (*)circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date, time]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]; status: [statusId, status]
1StandingsManagerManages championship standings and constructor/driver points calculations743 (*)constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; results: [resultId, raceId, driverId, constructorId, position, positionOrder, points]
2MediaCoordinatorProvides public information for media and fan engagement633 (*)circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, constructorRef, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [*]; races: [raceId, year, round, circuitId, name, date, time, url]; status: [statusId, status]
3DriverManagerManages driver information and personal details including date of birth432 (*)drivers: [*]; races: [raceId, year, round, name, date]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, statusId]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]
4SystemManagerFull administrative access for system maintenance and data integrity1394 (*)circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*]
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Role \\\\\\n\",\n \"0 RaceAnalyst \\n\",\n \"1 StandingsManager \\n\",\n \"2 MediaCoordinator \\n\",\n \"3 DriverManager \\n\",\n \"4 SystemManager \\n\",\n \"\\n\",\n \" Description \\\\\\n\",\n \"0 Analyzes race performance data including lap times, pit stops, and qualifying results \\n\",\n \"1 Manages championship standings and constructor/driver points calculations \\n\",\n \"2 Provides public information for media and fan engagement \\n\",\n \"3 Manages driver information and personal details including date of birth \\n\",\n \"4 Full administrative access for system maintenance and data integrity \\n\",\n \"\\n\",\n \" Tables Columns \\\\\\n\",\n \"0 9 65 (*) \\n\",\n \"1 7 43 (*) \\n\",\n \"2 6 33 (*) \\n\",\n \"3 4 32 (*) \\n\",\n \"4 13 94 (*) \\n\",\n \"\\n\",\n \" Policy \\n\",\n \"0 circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date, time]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]; status: [statusId, status] \\n\",\n \"1 constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; results: [resultId, raceId, driverId, constructorId, position, positionOrder, points] \\n\",\n \"2 circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, constructorRef, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [*]; races: [raceId, year, round, circuitId, name, date, time, url]; status: [statusId, status] \\n\",\n \"3 drivers: [*]; races: [raceId, year, round, name, date]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, statusId]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins] \\n\",\n \"4 circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*] \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Role x Table Matrix (column counts, * expanded) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
TablecircuitsconstructorResultsconstructorStandingsconstructorsdriverStandingsdriverslapTimespitStopsqualifyingracesresultsseasonsstatus
Role             
DriverManager0.0000000.0000000.0000000.0000007.0000009.0000000.0000000.0000000.0000005.00000011.0000000.0000000.000000
MediaCoordinator8.0000000.0000000.0000005.0000000.0000008.0000000.0000000.0000000.0000008.0000000.0000002.0000002.000000
RaceAnalyst6.0000000.0000000.0000004.0000000.0000007.0000006.0000007.0000009.0000007.00000017.0000000.0000002.000000
StandingsManager0.0000005.0000007.0000004.0000007.0000007.0000000.0000000.0000000.0000006.0000007.0000000.0000000.000000
SystemManager9.0000005.0000007.0000005.0000007.0000009.0000006.0000007.0000009.0000008.00000018.0000002.0000002.000000
\\n\"\n ],\n \"text/plain\": [\n \"\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"[SUMMARY] 1 database(s) selected: ['formula_1']\\n\",\n \"[NEXT] Edit hints in Cell 6.2, then run Cell 6.3\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.1 Select Database(s) & View Current State\\n\",\n \"# Supports single db (str) or multiple dbs (list)\\n\",\n \"\\n\",\n \"TARGET_DBS = [\\\"formula_1\\\"] # Single: \\\"toxicology\\\" or Multiple: [\\\"toxicology\\\", \\\"california_schools\\\"]\\n\",\n \"\\n\",\n \"# Normalize to list\\n\",\n \"if isinstance(TARGET_DBS, str):\\n\",\n \" TARGET_DBS = [TARGET_DBS]\\n\",\n \"\\n\",\n \"# Load current role assignments\\n\",\n \"with open(ROLE_ASSIGNMENTS_PATH, 'r') as f:\\n\",\n \" all_assignments = json.load(f)\\n\",\n \"\\n\",\n \"available_dbs = set(all_assignments.get('assignments', {}).keys())\\n\",\n \"valid_target_dbs = [db for db in TARGET_DBS if db in available_dbs]\\n\",\n \"invalid_dbs = [db for db in TARGET_DBS if db not in available_dbs]\\n\",\n \"\\n\",\n \"if invalid_dbs:\\n\",\n \" print(f\\\"[WARN] Databases not found: {invalid_dbs}\\\")\\n\",\n \" print(f\\\"Available: {sorted(available_dbs)}\\\\n\\\")\\n\",\n \"\\n\",\n \"# Store schemas for later use\\n\",\n \"target_schemas = {}\\n\",\n \"\\n\",\n \"for TARGET_DB in valid_target_dbs:\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"Database: {TARGET_DB}\\\")\\n\",\n \" print(f\\\"{'='*70}\\\")\\n\",\n \" \\n\",\n \" # --- Schema Summary ---\\n\",\n \" db_path = bird_db_dir / TARGET_DB / f\\\"{TARGET_DB}.sqlite\\\"\\n\",\n \" if db_path.exists():\\n\",\n \" target_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" target_schemas[TARGET_DB] = target_schema\\n\",\n \" \\n\",\n \" schema_rows = []\\n\",\n \" for table, info in target_schema.items():\\n\",\n \" for col in info['columns']:\\n\",\n \" schema_rows.append({\\n\",\n \" \\\"Table\\\": table,\\n\",\n \" \\\"Column\\\": col['name'],\\n\",\n \" \\\"Type\\\": col['type'],\\n\",\n \" \\\"PK\\\": \\\"Yes\\\" if col['pk'] else \\\"\\\",\\n\",\n \" \\\"FK\\\": col.get('fk', '') or \\\"\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" schema_df = pd.DataFrame(schema_rows)\\n\",\n \" print(f\\\"\\\\n=== Schema ({len(target_schema)} tables, {len(schema_df)} columns) ===\\\")\\n\",\n \" display(schema_df)\\n\",\n \" else:\\n\",\n \" print(f\\\"[ERROR] Database not found: {db_path}\\\")\\n\",\n \" target_schemas[TARGET_DB] = None\\n\",\n \" continue\\n\",\n \"\\n\",\n \" # --- Current Roles ---\\n\",\n \" if TARGET_DB in all_assignments.get('assignments', {}):\\n\",\n \" current_roles = all_assignments['assignments'][TARGET_DB]\\n\",\n \" \\n\",\n \" # Set display options for full content\\n\",\n \" pd.set_option('display.max_colwidth', None)\\n\",\n \" \\n\",\n \" roles_rows = []\\n\",\n \" for role_info in current_roles:\\n\",\n \" policy = role_info.get('policy', {})\\n\",\n \" total_access = count_policy_columns(policy, target_schema)\\n\",\n \" has_wildcard = has_wildcard_policy(policy)\\n\",\n \" cols_display = f\\\"{total_access}\\\" + (\\\" (*)\\\" if has_wildcard else \\\"\\\")\\n\",\n \" # Full policy string\\n\",\n \" policy_str = \\\"; \\\".join([\\n\",\n \" f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" \\n\",\n \" for t, c in policy.items()\\n\",\n \" ])\\n\",\n \" roles_rows.append({\\n\",\n \" \\\"Role\\\": role_info['role'],\\n\",\n \" \\\"Description\\\": role_info.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Columns\\\": cols_display,\\n\",\n \" \\\"Policy\\\": policy_str\\n\",\n \" })\\n\",\n \" \\n\",\n \" roles_df = pd.DataFrame(roles_rows)\\n\",\n \" print(f\\\"\\\\n=== Current Roles ({len(current_roles)}) ===\\\")\\n\",\n \" display(roles_df)\\n\",\n \" \\n\",\n \" pd.reset_option('display.max_colwidth')\\n\",\n \" \\n\",\n \" # Policy detail matrix\\n\",\n \" policy_rows = []\\n\",\n \" for role_info in current_roles:\\n\",\n \" policy = role_info.get('policy', {})\\n\",\n \" for table, cols in policy.items():\\n\",\n \" num_cols = count_policy_columns({table: cols}, target_schema)\\n\",\n \" policy_rows.append({\\n\",\n \" \\\"Role\\\": role_info['role'],\\n\",\n \" \\\"Table\\\": table,\\n\",\n \" \\\"NumCols\\\": num_cols\\n\",\n \" })\\n\",\n \" \\n\",\n \" if policy_rows:\\n\",\n \" policy_df = pd.DataFrame(policy_rows)\\n\",\n \" pivot = policy_df.pivot_table(index='Role', columns='Table', values='NumCols', fill_value=0)\\n\",\n \" print(\\\"\\\\n=== Role x Table Matrix (column counts, * expanded) ===\\\")\\n\",\n \" display(pivot.style.background_gradient(cmap='Blues', axis=None))\\n\",\n \" \\n\",\n \" # Quality issues\\n\",\n \" if 'report' in dir() and TARGET_DB in report.all_issues:\\n\",\n \" print(f\\\"\\\\n=== Quality Issues ===\\\")\\n\",\n \" issues = report.all_issues[TARGET_DB]\\n\",\n \" if TARGET_DB in report.deny_rate_metrics:\\n\",\n \" m = report.deny_rate_metrics[TARGET_DB]\\n\",\n \" issues_df = pd.DataFrame([{\\n\",\n \" \\\"Deny Rate\\\": f\\\"{m.deny_rate:.1f}%\\\",\\n\",\n \" \\\"All-Allow %\\\": f\\\"{m.all_allow_pct:.1f}%\\\",\\n\",\n \" \\\"Issues\\\": \\\"; \\\".join(issues)\\n\",\n \" }])\\n\",\n \" display(issues_df)\\n\",\n \" else:\\n\",\n \" print(f\\\"[ERROR] No roles found for {TARGET_DB}\\\")\\n\",\n \"\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"[SUMMARY] {len(valid_target_dbs)} database(s) selected: {valid_target_dbs}\\\")\\n\",\n \" print(\\\"[NEXT] Edit hints in Cell 6.2, then run Cell 6.3\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[INFO] No databases selected. Edit TARGET_DBS above and re-run.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 34,\n \"id\": \"f8416bc4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Applying shared hint to 1 database(s) ===\\n\",\n \"\\n\",\n \" ✓ formula_1: 13 tables, 94 columns\\n\",\n \"\\n\",\n \"[NEXT] Run Cell 6.3 to regenerate all 1 database(s)\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.2 Write Regeneration Hints (Human-in-the-Loop)\\n\",\n \"# Write ONE shared hint for all selected databases (they have similar issues)\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EDIT HERE: Shared problem description for all selected DBs\\n\",\n \"# Supports {db}, {num_tables}, {num_cols} placeholders\\n\",\n \"# ============================================================\\n\",\n \"# PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"# [PROBLEM]\\n\",\n \"# Low deny rate - almost all queries are allowed by all roles (roles too permissive)\\n\",\n \"# Low diversity - all roles have similar access patterns (coverage_std too low)\\n\",\n \"\\n\",\n \"\\n\",\n \"# [ROOT CAUSE]\\n\",\n \"# - Most roles can access most/all columns, so very few queries get denied\\n\",\n \"# - This defeats the purpose of RBAC - no meaningful access control\\n\",\n \"\\n\",\n \"# [DIRECTION]\\n\",\n \"# - Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"# - Create restrictive roles that only access specific subsets of data\\n\",\n \"# - Each role should have a clear, limited scope\\n\",\n \"# - Some roles should be restricted to fewer tables\\n\",\n \"# - Do not frequently giving non-admin roles \\\"*\\\" (all columns) access\\n\",\n \"# - Create clear functional boundaries between roles\\n\",\n \"# \\\"\\\"\\\"\\n\",\n \"\\n\",\n \"# All-denied cases - even SystemManager role cannot access some columns\\n\",\n \"# - Ensure SystemManager role has full access to all tables and columns\\n\",\n \"\\n\",\n \"\\n\",\n \"PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"[PROBLEM]\\n\",\n \"Low semantic alignment - roles do not align well with schema\\n\",\n \"All-denied cases - even SystemManager role cannot access some columns\\n\",\n \"\\n\",\n \"[ROOT CAUSE]\\n\",\n \"- This defeats the purpose of RBAC - no meaningful access control\\n\",\n \"\\n\",\n \"[DIRECTION]\\n\",\n \"- Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"- Ensure SystemManager role has full access to all tables and columns\\n\",\n \"- Review other roles to ensure they align with specific functional areas\\n\",\n \"- Each role should have a clear, limited scope\\n\",\n \"- Create meaningful semantic role names and descriptions that reflect their access patterns\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"# PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"# [PROBLEM]\\n\",\n \"# Low diversity - all roles have similar access patterns (coverage_std too low)\\n\",\n \"\\n\",\n \"# [ROOT CAUSE]\\n\",\n \"# - This defeats the purpose of RBAC - no meaningful access control differentiation\\n\",\n \"\\n\",\n \"# [DIRECTION]\\n\",\n \"# - Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"# - Create restrictive roles that only access specific subsets of data\\n\",\n \"# - Each role should have a clear, limited scope\\n\",\n \"# - Some roles should be restricted to fewer tables\\n\",\n \"# - Do not frequently giving non-admin roles \\\"*\\\" (all columns) access\\n\",\n \"# - Create clear functional boundaries between roles\\n\",\n \"# \\\"\\\"\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# Auto-apply to all selected databases (no need to edit below)\\n\",\n \"# ============================================================\\n\",\n \"REGENERATION_HINTS = {}\\n\",\n \"\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"=== Applying shared hint to {len(valid_target_dbs)} database(s) ===\\\\n\\\")\\n\",\n \" for db in valid_target_dbs:\\n\",\n \" schema = target_schemas.get(db, {})\\n\",\n \" num_tables = len(schema)\\n\",\n \" num_cols = sum(len(t['columns']) for t in schema.values())\\n\",\n \" \\n\",\n \" # Fill placeholders\\n\",\n \" REGENERATION_HINTS[db] = PROBLEM_TO_FIX.format(\\n\",\n \" db=db, num_tables=num_tables, num_cols=num_cols\\n\",\n \" )\\n\",\n \" print(f\\\" ✓ {db}: {num_tables} tables, {num_cols} columns\\\")\\n\",\n \"\\n\",\n \" print(f\\\"\\\\n[NEXT] Run Cell 6.3 to regenerate all {len(valid_target_dbs)} database(s)\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[INFO] No databases selected. Run Cell 6.1 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 68,\n \"id\": \"91109a7c\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Regenerating roles for 1 database(s)...\\n\",\n \"============================================================\\n\",\n \"\\n\",\n \"[formula_1] Generating...\\n\",\n \" ✓ 5 roles (5 valid)\\n\",\n \"\\n\",\n \"============================================================\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseStatusRolesValidTokens
0formula_1success553058
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Status Roles Valid Tokens\\n\",\n \"0 formula_1 success 5 5 3058\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"[OK] All databases regenerated. Run Cell 6.4 to preview.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.3 Execute Regeneration with Hints (supports multiple databases)\\n\",\n \"\\n\",\n \"def regenerate_single_database(db_name: str, hint: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Regenerate roles for a single database with guidance hints.\\\"\\\"\\\"\\n\",\n \" db_path = bird_db_dir / db_name / f\\\"{db_name}.sqlite\\\"\\n\",\n \" \\n\",\n \" if not db_path.exists():\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": \\\"Database not found\\\"}\\n\",\n \" \\n\",\n \" try:\\n\",\n \" db_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" db_schema_text = format_schema_for_prompt(db_schema, db_name)\\n\",\n \" \\n\",\n \" enhanced_system_prompt = f\\\"{COLUMN_LEVEL_SYSTEM_PROMPT}\\\\n\\\\n[OPTIMIZATION GUIDANCE]\\\\n{hint}\\\"\\n\",\n \" user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=db_schema_text)\\n\",\n \" \\n\",\n \" response = oracle.query(\\n\",\n \" prompt_sys=enhanced_system_prompt,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3,\\n\",\n \" top_p=0.9,\\n\",\n \" max_completion_tokens=DEFAULT_MAX_TOKENS\\n\",\n \" )\\n\",\n \" \\n\",\n \" llm_response = response['answer']\\n\",\n \" usage = response.get('usage', {})\\n\",\n \" roles = parse_column_level_roles(llm_response)\\n\",\n \" \\n\",\n \" if not roles:\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"parse_error\\\", \\n\",\n \" \\\"error\\\": \\\"Failed to parse LLM response\\\", \\\"raw_response\\\": llm_response[:500]}\\n\",\n \" \\n\",\n \" validation = validate_roles_against_schema(roles, str(db_path))\\n\",\n \" assignments = [{\\\"role\\\": r[\\\"role\\\"], \\\"description\\\": r.get(\\\"description\\\", \\\"\\\"), \\n\",\n \" \\\"policy\\\": r.get(\\\"columns\\\", {})} for r in roles]\\n\",\n \" \\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"success\\\", \\\"roles_count\\\": len(assignments),\\n\",\n \" \\\"valid_roles\\\": validation['valid_roles'], \\\"all_valid\\\": validation['all_valid'],\\n\",\n \" \\\"assignments\\\": assignments, \\\"usage\\\": usage, \\\"raw_response\\\": llm_response}\\n\",\n \" except Exception as e:\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": str(e)}\\n\",\n \"\\n\",\n \"# Execute for all target databases\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"Regenerating roles for {len(valid_target_dbs)} database(s)...\\\")\\n\",\n \" print(\\\"=\\\"*60)\\n\",\n \"\\n\",\n \" regenerated_results = {} # Store all results\\n\",\n \" all_success = True\\n\",\n \"\\n\",\n \" for db_name in valid_target_dbs:\\n\",\n \" hint = REGENERATION_HINTS.get(db_name, PROBLEM_TO_FIX)\\n\",\n \" print(f\\\"\\\\n[{db_name}] Generating...\\\")\\n\",\n \" \\n\",\n \" result = regenerate_single_database(db_name, hint)\\n\",\n \" regenerated_results[db_name] = result\\n\",\n \" \\n\",\n \" if result[\\\"status\\\"] == \\\"success\\\":\\n\",\n \" print(f\\\" ✓ {result['roles_count']} roles ({result['valid_roles']} valid)\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" ✗ {result.get('error', result['status'])}\\\")\\n\",\n \" all_success = False\\n\",\n \"\\n\",\n \" # Summary table\\n\",\n \" print(\\\"\\\\n\\\" + \\\"=\\\"*60)\\n\",\n \" result_df = pd.DataFrame([{\\n\",\n \" \\\"Database\\\": r[\\\"database\\\"],\\n\",\n \" \\\"Status\\\": r[\\\"status\\\"],\\n\",\n \" \\\"Roles\\\": r.get(\\\"roles_count\\\", \\\"N/A\\\"),\\n\",\n \" \\\"Valid\\\": r.get(\\\"valid_roles\\\", \\\"N/A\\\"),\\n\",\n \" \\\"Tokens\\\": r.get(\\\"usage\\\", {}).get(\\\"total_tokens\\\", \\\"N/A\\\")\\n\",\n \" } for r in regenerated_results.values()])\\n\",\n \" display(result_df)\\n\",\n \"\\n\",\n \" if all_success:\\n\",\n \" print(\\\"\\\\n[OK] All databases regenerated. Run Cell 6.4 to preview.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"\\\\n[WARN] Some databases failed. Check errors above.\\\")\\n\",\n \"else:\\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"[INFO] No databases selected. Run Cell 6.1 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 69,\n \"id\": \"a2b0ba98\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"Database: formula_1\\n\",\n \"======================================================================\\n\",\n \"\\n\",\n \"=== NEW Roles (5) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
RoleDescriptionTablesColsPolicy
0SystemManagerFull administrative access for system maintenance and data management1394 (*)circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*]
1RaceAnalystAnalyzes race performance data including lap times, pit stops, and qualifying results861circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; lapTimes: [raceId, driverId, lap, position, time, milliseconds]; pitStops: [raceId, driverId, stop, lap, time, duration, milliseconds]; qualifying: [qualifyId, raceId, driverId, constructorId, number, position, q1, q2, q3]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]
2StandingsManagerManages and monitors championship standings for drivers and constructors742constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, name, date]; constructorResults: [constructorResultsId, raceId, constructorId, points, status]; constructorStandings: [constructorStandingsId, raceId, constructorId, points, position, positionText, wins]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, points, position, positionText, statusId]
3PublicRelationsAccesses public information about circuits, drivers, constructors, and race schedules631circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [year, url]; races: [raceId, year, round, circuitId, name, date, url]; status: [statusId, status]
4DriverManagerManages driver information and personal details including date of birth432drivers: [driverId, driverRef, number, code, forename, surname, dob, nationality]; races: [raceId, year, round, name, date]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionText, positionOrder, points, laps, statusId]
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Role \\\\\\n\",\n \"0 SystemManager \\n\",\n \"1 RaceAnalyst \\n\",\n \"2 StandingsManager \\n\",\n \"3 PublicRelations \\n\",\n \"4 DriverManager \\n\",\n \"\\n\",\n \" Description \\\\\\n\",\n \"0 Full administrative access for system maintenance and data management \\n\",\n \"1 Analyzes race performance data including lap times, pit stops, and qualifying results \\n\",\n \"2 Manages and monitors championship standings for drivers and constructors \\n\",\n \"3 Accesses public information about circuits, drivers, constructors, and race schedules \\n\",\n \"4 Manages driver information and personal details including date of birth \\n\",\n \"\\n\",\n \" Tables Cols \\\\\\n\",\n \"0 13 94 (*) \\n\",\n \"1 8 61 \\n\",\n \"2 7 42 \\n\",\n \"3 6 31 \\n\",\n \"4 4 32 \\n\",\n \"\\n\",\n \" Policy \\n\",\n \"0 circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*] \\n\",\n \"1 circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; lapTimes: [raceId, driverId, lap, position, time, milliseconds]; pitStops: [raceId, driverId, stop, lap, time, duration, milliseconds]; qualifying: [qualifyId, raceId, driverId, constructorId, number, position, q1, q2, q3]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId] \\n\",\n \"2 constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, name, date]; constructorResults: [constructorResultsId, raceId, constructorId, points, status]; constructorStandings: [constructorStandingsId, raceId, constructorId, points, position, positionText, wins]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, points, position, positionText, statusId] \\n\",\n \"3 circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [year, url]; races: [raceId, year, round, circuitId, name, date, url]; status: [statusId, status] \\n\",\n \"4 drivers: [driverId, driverRef, number, code, forename, surname, dob, nationality]; races: [raceId, year, round, name, date]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionText, positionOrder, points, laps, statusId] \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Quality Comparison ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
MetricOLDNEWThresholdStatus
0Roles55NaNNaN
1Avg Coverage65.5%55.3%<85%OK
2Coverage Std0.1830.251>0.065OK
3Max Overlap87.3%57.4%<80%OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Metric OLD NEW Threshold Status\\n\",\n \"0 Roles 5 5 NaN NaN\\n\",\n \"1 Avg Coverage 65.5% 55.3% <85% OK\\n\",\n \"2 Coverage Std 0.183 0.251 >0.065 OK\\n\",\n \"3 Max Overlap 87.3% 57.4% <80% OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[OK] formula_1: All quality checks passed\\n\",\n \"\\n\",\n \"======================================================================\\n\",\n \"[DECISION] Satisfied? Run Cell 6.5 to apply. Otherwise edit Cell 6.2 and re-run 6.3.\\n\",\n \"[TIP] Use Cell 6.4.1 to select specific roles from OLD/NEW\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.4 Preview Regenerated Roles (Compare OLD vs NEW + Quality Check)\\n\",\n \"# Supports multiple databases\\n\",\n \"import numpy as np\\n\",\n \"from src.role_evaluator.quality_metrics import RoleQualityEvaluator\\n\",\n \"\\n\",\n \"pd.set_option('display.max_colwidth', None)\\n\",\n \"pd.set_option('display.max_rows', None)\\n\",\n \"pd.set_option('display.width', None)\\n\",\n \"\\n\",\n \"if 'regenerated_results' in dir() and regenerated_results:\\n\",\n \" for db_name, regen_result in regenerated_results.items():\\n\",\n \" if regen_result[\\\"status\\\"] != \\\"success\\\":\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"[SKIP] {db_name}: {regen_result.get('error', 'failed')}\\\")\\n\",\n \" continue\\n\",\n \" \\n\",\n \" regenerated_assignments = regen_result[\\\"assignments\\\"]\\n\",\n \" target_schema = target_schemas.get(db_name)\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"Database: {db_name}\\\")\\n\",\n \" print(f\\\"{'='*70}\\\")\\n\",\n \" \\n\",\n \" # --- NEW Role Summary ---\\n\",\n \" new_summary = []\\n\",\n \" for r in regenerated_assignments:\\n\",\n \" policy = r.get('policy', {})\\n\",\n \" total_cols = count_policy_columns(policy, target_schema)\\n\",\n \" has_wc = has_wildcard_policy(policy)\\n\",\n \" cols_display = f\\\"{total_cols}\\\" + (\\\" (*)\\\" if has_wc else \\\"\\\")\\n\",\n \" policy_str = \\\"; \\\".join([\\n\",\n \" f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" \\n\",\n \" for t, c in policy.items()\\n\",\n \" ])\\n\",\n \" new_summary.append({\\n\",\n \" \\\"Role\\\": r['role'],\\n\",\n \" \\\"Description\\\": r.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Cols\\\": cols_display,\\n\",\n \" \\\"Policy\\\": policy_str\\n\",\n \" })\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n=== NEW Roles ({len(regenerated_assignments)}) ===\\\")\\n\",\n \" display(pd.DataFrame(new_summary))\\n\",\n \" \\n\",\n \" # --- Quality Metrics ---\\n\",\n \" if target_schema:\\n\",\n \" total_schema_cols = sum(len(t['columns']) for t in target_schema.values())\\n\",\n \" else:\\n\",\n \" total_schema_cols = 10\\n\",\n \" \\n\",\n \" # NEW metrics\\n\",\n \" new_coverages = [count_policy_columns(r.get('policy', {}), target_schema) / total_schema_cols \\n\",\n \" for r in regenerated_assignments]\\n\",\n \" new_avg_cov = np.mean(new_coverages)\\n\",\n \" new_cov_std = np.std(new_coverages)\\n\",\n \" \\n\",\n \" new_max_overlap = 0.0\\n\",\n \" non_admin_new = [r for r in regenerated_assignments if 'admin' not in r['role'].lower()]\\n\",\n \" for i, r1 in enumerate(non_admin_new):\\n\",\n \" set1 = RoleQualityEvaluator.policy_to_column_set(r1.get('policy', {}))\\n\",\n \" for r2 in non_admin_new[i+1:]:\\n\",\n \" set2 = RoleQualityEvaluator.policy_to_column_set(r2.get('policy', {}))\\n\",\n \" new_max_overlap = max(new_max_overlap, RoleQualityEvaluator.jaccard_similarity(set1, set2))\\n\",\n \" \\n\",\n \" # OLD metrics\\n\",\n \" old_roles = all_assignments.get('assignments', {}).get(db_name, [])\\n\",\n \" if old_roles:\\n\",\n \" old_coverages = [count_policy_columns(r.get('policy', {}), target_schema) / total_schema_cols \\n\",\n \" for r in old_roles]\\n\",\n \" old_avg_cov = np.mean(old_coverages)\\n\",\n \" old_cov_std = np.std(old_coverages)\\n\",\n \" \\n\",\n \" old_max_overlap = 0.0\\n\",\n \" non_admin_old = [r for r in old_roles if 'admin' not in r['role'].lower()]\\n\",\n \" for i, r1 in enumerate(non_admin_old):\\n\",\n \" set1 = RoleQualityEvaluator.policy_to_column_set(r1.get('policy', {}))\\n\",\n \" for r2 in non_admin_old[i+1:]:\\n\",\n \" set2 = RoleQualityEvaluator.policy_to_column_set(r2.get('policy', {}))\\n\",\n \" old_max_overlap = max(old_max_overlap, RoleQualityEvaluator.jaccard_similarity(set1, set2))\\n\",\n \" else:\\n\",\n \" old_avg_cov, old_cov_std, old_max_overlap = 0, 0, 0\\n\",\n \" \\n\",\n \" # Comparison table (using QUALITY_THRESHOLDS from Cell 5.1)\\n\",\n \" def status(metric, val):\\n\",\n \" if metric == \\\"Coverage\\\": \\n\",\n \" return \\\"WARN\\\" if val > QUALITY_THRESHOLDS.get(\\\"coverage_max\\\", 0.90) else \\\"OK\\\"\\n\",\n \" if metric == \\\"CovStd\\\": \\n\",\n \" return \\\"WARN\\\" if val < QUALITY_THRESHOLDS.get(\\\"coverage_std_min\\\", 0.08) else \\\"OK\\\"\\n\",\n \" if metric == \\\"MaxOverlap\\\": \\n\",\n \" return \\\"WARN\\\" if val > QUALITY_THRESHOLDS.get(\\\"max_overlap\\\", 0.80) else \\\"OK\\\"\\n\",\n \" return \\\"OK\\\"\\n\",\n \" \\n\",\n \" quality_df = pd.DataFrame([\\n\",\n \" {\\\"Metric\\\": \\\"Roles\\\", \\\"OLD\\\": len(old_roles), \\\"NEW\\\": len(regenerated_assignments)},\\n\",\n \" {\\\"Metric\\\": \\\"Avg Coverage\\\", \\\"OLD\\\": f\\\"{old_avg_cov:.1%}\\\", \\\"NEW\\\": f\\\"{new_avg_cov:.1%}\\\", \\n\",\n \" \\\"Threshold\\\": f\\\"<{QUALITY_THRESHOLDS.get('coverage_max', 0.90):.0%}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"Coverage\\\", new_avg_cov)},\\n\",\n \" {\\\"Metric\\\": \\\"Coverage Std\\\", \\\"OLD\\\": f\\\"{old_cov_std:.3f}\\\", \\\"NEW\\\": f\\\"{new_cov_std:.3f}\\\",\\n\",\n \" \\\"Threshold\\\": f\\\">{QUALITY_THRESHOLDS.get('coverage_std_min', 0.08)}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"CovStd\\\", new_cov_std)},\\n\",\n \" {\\\"Metric\\\": \\\"Max Overlap\\\", \\\"OLD\\\": f\\\"{old_max_overlap:.1%}\\\", \\\"NEW\\\": f\\\"{new_max_overlap:.1%}\\\",\\n\",\n \" \\\"Threshold\\\": f\\\"<{QUALITY_THRESHOLDS.get('max_overlap', 0.80):.0%}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"MaxOverlap\\\", new_max_overlap)},\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Quality Comparison ===\\\")\\n\",\n \" display(quality_df)\\n\",\n \" \\n\",\n \" warn_count = quality_df['Status'].eq('WARN').sum() if 'Status' in quality_df.columns else 0\\n\",\n \" if warn_count == 0:\\n\",\n \" print(f\\\"[OK] {db_name}: All quality checks passed\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\"[WARN] {db_name}: {warn_count} issue(s)\\\")\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(\\\"[DECISION] Satisfied? Run Cell 6.5 to apply. Otherwise edit Cell 6.2 and re-run 6.3.\\\")\\n\",\n \" print(\\\"[TIP] Use Cell 6.4.1 to select specific roles from OLD/NEW\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[WARN] No regenerated results. Run Cell 6.3 first.\\\")\\n\",\n \"\\n\",\n \"pd.reset_option('display.max_colwidth')\\n\",\n \"pd.reset_option('display.max_rows')\\n\",\n \"pd.reset_option('display.width')\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 70,\n \"id\": \"f003a014\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Role Selection Summary ===\\n\",\n \"\\n\",\n \"============================================================\\n\",\n \"Database: formula_1\\n\",\n \" From OLD (0): (none)\\n\",\n \" From NEW (4): ['SystemManager', 'RaceAnalyst', 'PublicRelations', 'DriverManager']\\n\",\n \" Combined: 4 roles\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
SourceRoleDescriptionTablesPolicy
0NEWSystemManagerFull administrative access for system maintena...13circuits: [*]; constructors: [*]; drivers: [*]...
1NEWRaceAnalystAnalyzes race performance data including lap t...8circuits: [circuitId, name, location, country,...
2NEWPublicRelationsAccesses public information about circuits, dr...6circuits: [circuitId, name, location, country,...
3NEWDriverManagerManages driver information and personal detail...4drivers: [driverId, driverRef, number, code, f...
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Source Role Description \\\\\\n\",\n \"0 NEW SystemManager Full administrative access for system maintena... \\n\",\n \"1 NEW RaceAnalyst Analyzes race performance data including lap t... \\n\",\n \"2 NEW PublicRelations Accesses public information about circuits, dr... \\n\",\n \"3 NEW DriverManager Manages driver information and personal detail... \\n\",\n \"\\n\",\n \" Tables Policy \\n\",\n \"0 13 circuits: [*]; constructors: [*]; drivers: [*]... \\n\",\n \"1 8 circuits: [circuitId, name, location, country,... \\n\",\n \"2 6 circuits: [circuitId, name, location, country,... \\n\",\n \"3 4 drivers: [driverId, driverRef, number, code, f... \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"============================================================\\n\",\n \"[NEXT] Run Cell 6.5 to apply combined role sets\\n\",\n \"[TIP] Edit ROLE_SELECTION above to customize, then re-run this cell\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.4.1 Select & Combine Roles from OLD and NEW\\n\",\n \"# Human expert picks best roles from both versions to create final role set\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EDIT HERE: Specify which roles to keep from each version\\n\",\n \"# Format: {\\\"db_name\\\": {\\\"old\\\": [role_names], \\\"new\\\": [role_names]}}\\n\",\n \"# Leave empty [] to skip a version, or use [\\\"*\\\"] to keep all from that version\\n\",\n \"# ============================================================\\n\",\n \"ROLE_SELECTION = {\\n\",\n \" \\\"formula_1\\\": {\\n\",\n \" \\\"old\\\": [], # e.g., [\\\"DataAnalyst\\\", \\\"Researcher\\\"]\\n\",\n \" \\\"new\\\": [\\\"SystemManager\\\", \\\"RaceAnalyst\\\", \\\"PublicRelations\\\", \\\"DriverManager\\\"], # keep all new roles\\n\",\n \" },\\n\",\n \" # \\\"financial\\\": {\\n\",\n \" # \\\"old\\\": [],\\n\",\n \" # \\\"new\\\": [\\\"*\\\"],\\n\",\n \" # },\\n\",\n \"}\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# Process selections and create combined role sets\\n\",\n \"# ============================================================\\n\",\n \"combined_results = {}\\n\",\n \"\\n\",\n \"if 'regenerated_results' in dir() and regenerated_results:\\n\",\n \" print(\\\"=== Role Selection Summary ===\\\\n\\\")\\n\",\n \" \\n\",\n \" for db_name in valid_target_dbs:\\n\",\n \" selection = ROLE_SELECTION.get(db_name, {\\\"old\\\": [], \\\"new\\\": [\\\"*\\\"]})\\n\",\n \" old_keep = selection.get(\\\"old\\\", [])\\n\",\n \" new_keep = selection.get(\\\"new\\\", [\\\"*\\\"])\\n\",\n \" \\n\",\n \" # Get OLD roles\\n\",\n \" old_roles = all_assignments.get('assignments', {}).get(db_name, [])\\n\",\n \" old_role_dict = {r['role']: r for r in old_roles}\\n\",\n \" \\n\",\n \" # Get NEW roles\\n\",\n \" regen_result = regenerated_results.get(db_name, {})\\n\",\n \" if regen_result.get(\\\"status\\\") != \\\"success\\\":\\n\",\n \" print(f\\\"[SKIP] {db_name}: regeneration failed\\\")\\n\",\n \" continue\\n\",\n \" new_roles = regen_result[\\\"assignments\\\"]\\n\",\n \" new_role_dict = {r['role']: r for r in new_roles}\\n\",\n \" \\n\",\n \" # Build combined role set\\n\",\n \" combined_roles = []\\n\",\n \" selected_from_old = []\\n\",\n \" selected_from_new = []\\n\",\n \" \\n\",\n \" # Select from OLD\\n\",\n \" if old_keep == [\\\"*\\\"]:\\n\",\n \" combined_roles.extend(old_roles)\\n\",\n \" selected_from_old = [r['role'] for r in old_roles]\\n\",\n \" else:\\n\",\n \" for role_name in old_keep:\\n\",\n \" if role_name in old_role_dict:\\n\",\n \" combined_roles.append(old_role_dict[role_name])\\n\",\n \" selected_from_old.append(role_name)\\n\",\n \" else:\\n\",\n \" print(f\\\" [WARN] {db_name}: OLD role '{role_name}' not found\\\")\\n\",\n \" \\n\",\n \" # Select from NEW\\n\",\n \" if new_keep == [\\\"*\\\"]:\\n\",\n \" combined_roles.extend(new_roles)\\n\",\n \" selected_from_new = [r['role'] for r in new_roles]\\n\",\n \" else:\\n\",\n \" for role_name in new_keep:\\n\",\n \" if role_name in new_role_dict:\\n\",\n \" combined_roles.append(new_role_dict[role_name])\\n\",\n \" selected_from_new.append(role_name)\\n\",\n \" else:\\n\",\n \" print(f\\\" [WARN] {db_name}: NEW role '{role_name}' not found\\\")\\n\",\n \" \\n\",\n \" combined_results[db_name] = combined_roles\\n\",\n \" \\n\",\n \" # Display summary\\n\",\n \" print(f\\\"{'='*60}\\\")\\n\",\n \" print(f\\\"Database: {db_name}\\\")\\n\",\n \" print(f\\\" From OLD ({len(selected_from_old)}): {selected_from_old if selected_from_old else '(none)'}\\\")\\n\",\n \" print(f\\\" From NEW ({len(selected_from_new)}): {selected_from_new if selected_from_new else '(none)'}\\\")\\n\",\n \" print(f\\\" Combined: {len(combined_roles)} roles\\\")\\n\",\n \" \\n\",\n \" # Show combined roles table\\n\",\n \" target_schema = target_schemas.get(db_name)\\n\",\n \" combined_summary = []\\n\",\n \" for r in combined_roles:\\n\",\n \" policy = r.get('policy', {})\\n\",\n \" source = \\\"OLD\\\" if r['role'] in old_role_dict and r['role'] not in [nr['role'] for nr in new_roles] else \\\"NEW\\\"\\n\",\n \" if r['role'] in old_role_dict and r['role'] in [nr['role'] for nr in new_roles]:\\n\",\n \" source = \\\"NEW\\\" # Prefer NEW if same name exists in both\\n\",\n \" combined_summary.append({\\n\",\n \" \\\"Source\\\": source,\\n\",\n \" \\\"Role\\\": r['role'],\\n\",\n \" \\\"Description\\\": r.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Policy\\\": \\\"; \\\".join([f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" for t, c in policy.items()])\\n\",\n \" })\\n\",\n \" \\n\",\n \" display(pd.DataFrame(combined_summary))\\n\",\n \" print()\\n\",\n \" \\n\",\n \" print(\\\"=\\\"*60)\\n\",\n \" print(f\\\"[NEXT] Run Cell 6.5 to apply combined role sets\\\")\\n\",\n \" print(\\\"[TIP] Edit ROLE_SELECTION above to customize, then re-run this cell\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[WARN] No regenerated results. Run Cell 6.3 first.\\\")\\n\",\n \" print(\\\"\\\\n[HINT] Available roles to select from:\\\")\\n\",\n \" print(\\\" OLD: roles from current assignments\\\")\\n\",\n \" print(\\\" NEW: roles from regeneration\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 71,\n \"id\": \"6cb24c7d\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[MODE] Applying COMBINED role sets (from Cell 6.4.1 selection)\\n\",\n \"\\n\",\n \"=== Changes Applied ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseOld RolesNew RolesSource
0formula_154Combined (OLD+NEW)
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Old Roles New Roles Source\\n\",\n \"0 formula_1 5 4 Combined (OLD+NEW)\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"Saved to: bird_column_level_rbac_assignments_v2_20251230.json\\n\",\n \"\\n\",\n \"[OK] State cleared. Select new database(s) to continue.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.5 Apply Changes (Save Combined Role Sets)\\n\",\n \"# Uses combined_results from Cell 6.4.1 (selected from OLD + NEW)\\n\",\n \"from datetime import datetime\\n\",\n \"\\n\",\n \"APPLY_CHANGES = True # Set to True to confirm\\n\",\n \"\\n\",\n \"if APPLY_CHANGES:\\n\",\n \" # Prefer combined_results (from selection), fallback to regenerated_results\\n\",\n \" use_combined = 'combined_results' in dir() and combined_results\\n\",\n \" use_regenerated = 'regenerated_results' in dir() and regenerated_results\\n\",\n \" \\n\",\n \" if use_combined:\\n\",\n \" print(\\\"[MODE] Applying COMBINED role sets (from Cell 6.4.1 selection)\\\\n\\\")\\n\",\n \" applied = []\\n\",\n \" \\n\",\n \" for db_name, combined_roles in combined_results.items():\\n\",\n \" if not combined_roles:\\n\",\n \" continue\\n\",\n \" \\n\",\n \" old_count = len(all_assignments.get('assignments', {}).get(db_name, []))\\n\",\n \" all_assignments['assignments'][db_name] = combined_roles\\n\",\n \" applied.append({\\n\",\n \" \\\"Database\\\": db_name,\\n\",\n \" \\\"Old Roles\\\": old_count,\\n\",\n \" \\\"New Roles\\\": len(combined_roles),\\n\",\n \" \\\"Source\\\": \\\"Combined (OLD+NEW)\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" if applied:\\n\",\n \" OUTPUT_DIR = project_root / 'outputs'\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = OUTPUT_DIR / f'bird_column_level_rbac_assignments_v2_{today}.json'\\n\",\n \" with open(output_path, 'w') as f:\\n\",\n \" json.dump(all_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \" \\n\",\n \" print(\\\"=== Changes Applied ===\\\")\\n\",\n \" display(pd.DataFrame(applied))\\n\",\n \" print(f\\\"\\\\nSaved to: {output_path.name}\\\")\\n\",\n \" \\n\",\n \" # Clear state\\n\",\n \" combined_results = {}\\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"\\\\n[OK] State cleared. Select new database(s) to continue.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No combined role sets to apply. Run Cell 6.4.1 first.\\\")\\n\",\n \" \\n\",\n \" elif use_regenerated:\\n\",\n \" print(\\\"[MODE] Applying ALL NEW roles (no selection made)\\\\n\\\")\\n\",\n \" applied = []\\n\",\n \" \\n\",\n \" for db_name, regen_result in regenerated_results.items():\\n\",\n \" if regen_result[\\\"status\\\"] != \\\"success\\\":\\n\",\n \" continue\\n\",\n \" \\n\",\n \" old_count = len(all_assignments.get('assignments', {}).get(db_name, []))\\n\",\n \" all_assignments['assignments'][db_name] = regen_result[\\\"assignments\\\"]\\n\",\n \" applied.append({\\n\",\n \" \\\"Database\\\": db_name,\\n\",\n \" \\\"Old Roles\\\": old_count,\\n\",\n \" \\\"New Roles\\\": len(regen_result[\\\"assignments\\\"]),\\n\",\n \" \\\"Source\\\": \\\"All NEW\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" if applied:\\n\",\n \" OUTPUT_DIR = project_root / 'outputs'\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = OUTPUT_DIR / f'bird_column_level_rbac_assignments_v2_{today}.json'\\n\",\n \" with open(output_path, 'w') as f:\\n\",\n \" json.dump(all_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \" \\n\",\n \" print(\\\"=== Changes Applied ===\\\")\\n\",\n \" display(pd.DataFrame(applied))\\n\",\n \" print(f\\\"\\\\nSaved to: {output_path.name}\\\")\\n\",\n \" \\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"\\\\n[OK] State cleared. Select new database(s) to continue.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No successful regenerations to apply.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No results to apply. Run Cell 6.3 and optionally Cell 6.4.1 first.\\\")\\n\",\n \"else:\\n\",\n \" has_combined = 'combined_results' in dir() and combined_results\\n\",\n \" has_regenerated = 'regenerated_results' in dir() and regenerated_results\\n\",\n \" \\n\",\n \" if has_combined:\\n\",\n \" print(f\\\"[INFO] {len(combined_results)} database(s) with COMBINED role sets ready\\\")\\n\",\n \" print(\\\"[TIP] These are your custom selections from OLD + NEW\\\")\\n\",\n \" elif has_regenerated:\\n\",\n \" success_count = sum(1 for r in regenerated_results.values() if r[\\\"status\\\"] == \\\"success\\\")\\n\",\n \" print(f\\\"[INFO] {success_count} database(s) with ALL NEW roles ready\\\")\\n\",\n \" print(\\\"[TIP] Run Cell 6.4.1 to select specific roles from OLD/NEW\\\")\\n\",\n \" \\n\",\n \" print(\\\"\\\\n[INFO] APPLY_CHANGES is False. Set to True and re-run to apply.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 72,\n \"id\": \"f1bd0bc2\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Regenerating RBAC Dataset ===\\n\",\n \"Role assignments: bird_column_level_rbac_assignments_v2_20251230.json\\n\",\n \"BIRD data: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev.json\\n\",\n \"Generating column-level RBAC dataset...\\n\",\n \" Roles per DB: None\\n\",\n \" Queries per role: all\\n\",\n \"Current ratio (allowed): 50.41%\\n\",\n \" Allowed: 3656, Denied: 3596\\n\",\n \"\\n\",\n \"Dataset saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251230.json\\n\",\n \"Metadata saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251230_metadata.json\\n\",\n \" Total entries: 7252\\n\",\n \" Allowed: 3656 (50.4%)\\n\",\n \" Denied: 3596 (49.6%)\\n\",\n \"\\n\",\n \"✓ Dataset saved to: column_level_rbac_dataset_bird_20251230.json\\n\",\n \"\\n\",\n \"=== Dataset Statistics ===\\n\",\n \" total_entries: 7252\\n\",\n \" allowed: 3656\\n\",\n \" denied: 3596\\n\",\n \" allowed_ratio: 0.5041367898510756\\n\",\n \"\\n\",\n \"Per-database distribution:\\n\",\n \" california_schools: allowed=118, denied=327\\n\",\n \" card_games: allowed=507, denied=448\\n\",\n \" codebase_community: allowed=578, denied=352\\n\",\n \" debit_card_specializing: allowed=174, denied=210\\n\",\n \" european_football_2: allowed=277, denied=368\\n\",\n \" financial: allowed=156, denied=374\\n\",\n \" formula_1: allowed=385, denied=311\\n\",\n \" student_club: allowed=396, denied=394\\n\",\n \" superhero: allowed=328, denied=317\\n\",\n \" thrombosis_prediction: allowed=432, denied=220\\n\",\n \" toxicology: allowed=305, denied=275\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.6 Regenerate RBAC Dataset with Updated Role Assignments\\n\",\n \"# Run this after Cell 6.5 to create the final dataset\\n\",\n \"\\n\",\n \"from datetime import datetime\\n\",\n \"import importlib\\n\",\n \"\\n\",\n \"# IMPORTANT: Reload ALL dependent modules to pick up CTE parsing fix\\n\",\n \"import src.processors.column_extractor\\n\",\n \"import src.processors.column_permission_checker\\n\",\n \"import src.processors.column_level_rbac_generator\\n\",\n \"\\n\",\n \"importlib.reload(src.processors.column_extractor)\\n\",\n \"importlib.reload(src.processors.column_permission_checker)\\n\",\n \"importlib.reload(src.processors.column_level_rbac_generator)\\n\",\n \"\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator\\n\",\n \"\\n\",\n \"# Find the updated role assignments file (v2 if exists, otherwise latest)\\n\",\n \"v2_files = sorted(glob.glob(str(project_root / 'outputs' / 'bird_column_level_rbac_assignments_v2_*.json')))\\n\",\n \"if v2_files:\\n\",\n \" UPDATED_ROLE_PATH = v2_files[-1]\\n\",\n \"else:\\n\",\n \" role_files = sorted(glob.glob(str(project_root / 'outputs' / 'column_level_role_assignments_bird_*.json')))\\n\",\n \" UPDATED_ROLE_PATH = role_files[-1] if role_files else None\\n\",\n \"\\n\",\n \"if UPDATED_ROLE_PATH:\\n\",\n \" print(f\\\"=== Regenerating RBAC Dataset ===\\\")\\n\",\n \" print(f\\\"Role assignments: {Path(UPDATED_ROLE_PATH).name}\\\")\\n\",\n \" print(f\\\"BIRD data: {BIRD_DATA_PATH}\\\")\\n\",\n \" \\n\",\n \" # Initialize generator with updated roles\\n\",\n \" generator = ColumnLevelRBACGenerator(\\n\",\n \" role_assignments_path=UPDATED_ROLE_PATH,\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH),\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" project_root=str(project_root),\\n\",\n \" seed=42\\n\",\n \" )\\n\",\n \" \\n\",\n \" # Generate dataset\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = project_root / 'outputs' / f'column_level_rbac_dataset_bird_{today}.json'\\n\",\n \" \\n\",\n \" full_stats = generator.generate_and_save(\\n\",\n \" output_path=str(output_path),\\n\",\n \" roles_per_db=None,\\n\",\n \" queries_per_role=None\\n\",\n \" )\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n✓ Dataset saved to: {output_path.name}\\\")\\n\",\n \" print(f\\\"\\\\n=== Dataset Statistics ===\\\")\\n\",\n \" for k, v in full_stats.items():\\n\",\n \" if k == 'by_database':\\n\",\n \" print(f\\\"\\\\nPer-database distribution:\\\")\\n\",\n \" for db_id, counts in sorted(v.items()):\\n\",\n \" print(f\\\" {db_id}: allowed={counts['allowed']}, denied={counts['denied']}\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[ERROR] No role assignments file found. Run Cell 6.5 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"a9345c97\",\n \"metadata\": {},\n \"source\": [\n \"## 7. Summary\\n\",\n \"\\n\",\n \"### Generated Files\\n\",\n \"- `outputs/column_level_role_assignments_bird_YYYYMMDD.json` - Role assignments with column-level policies\\n\",\n \"- `outputs/bird_column_level_rbac_assignments_v2_YYYYMMDD.json` - Updated role assignments after regeneration\\n\",\n \"- `outputs/column_level_rbac_dataset_bird_YYYYMMDD.json` - Column-Level RBAC dataset\\n\",\n \"\\n\",\n \"### Workflow\\n\",\n \"\\n\",\n \"| Section | Description |\\n\",\n \"|---------|-------------|\\n\",\n \"| **3** | Batch process all BIRD databases to generate initial roles |\\n\",\n \"| **4** | Generate RBAC dataset from role assignments |\\n\",\n \"| **5** | Quality assessment with configurable thresholds |\\n\",\n \"| **6.1** | Select problematic database(s) and view current state |\\n\",\n \"| **6.2** | Write regeneration hints with problem description |\\n\",\n \"| **6.3** | Execute LLM regeneration with hints |\\n\",\n \"| **6.4** | Preview OLD vs NEW roles with quality comparison |\\n\",\n \"| **6.4.1** | Select & combine best roles from OLD and NEW |\\n\",\n \"| **6.5** | Apply changes (save updated role assignments) |\\n\",\n \"| **6.6** | Regenerate RBAC dataset with updated roles |\\n\",\n \"\\n\",\n \"### Quality Assessment Module (Section 5)\\n\",\n \"\\n\",\n \"```python\\n\",\n \"from src.role_evaluator import RoleQualityEvaluator, RoleQualityVisualizer\\n\",\n \"\\n\",\n \"evaluator = RoleQualityEvaluator(\\n\",\n \" role_assignments_path=\\\"outputs/column_level_role_assignments_bird.json\\\",\\n\",\n \" dataset_path=\\\"outputs/column_level_rbac_dataset_bird.json\\\",\\n\",\n \" schema_dir=\\\"data/Bird/dev_20251106/dev_databases\\\",\\n\",\n \" embed_model=\\\"BAAI/bge-small-en-v1.5\\\" # or \\\"text-embedding-3-small\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"report = evaluator.evaluate_all()\\n\",\n \"visualizer = RoleQualityVisualizer(evaluator=evaluator, report=report)\\n\",\n \"visualizer.plot_quality_dashboard()\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Quality Thresholds (Configurable)\\n\",\n \"\\n\",\n \"| Metric | Default | Description |\\n\",\n \"|--------|---------|-------------|\\n\",\n \"| `deny_rate_min` | 5% | Warn if deny rate below (roles too permissive) |\\n\",\n \"| `coverage_max` | 90% | Warn if avg coverage above (roles too broad) |\\n\",\n \"| `coverage_std_min` | 0.08 | Warn if coverage std below (low diversity) |\\n\",\n \"| `max_overlap` | 80% | Warn if max overlap above (redundant roles) |\\n\",\n \"\\n\",\n \"### External Modules\\n\",\n \"\\n\",\n \"1. **`src/role_evaluator/quality_metrics.py`** - Quality metrics computation\\n\",\n \" - `RoleQualityEvaluator`: Comprehensive evaluator\\n\",\n \" - `DenyRateMetrics`, `SemanticMetrics`, `OverlapMetrics`: Data classes\\n\",\n \" - `print_quality_report()`: Formatted report output\\n\",\n \"\\n\",\n \"2. **`src/role_evaluator/quality_visualizer.py`** - Visualization suite\\n\",\n \" - `plot_deny_rate_distribution()`: Permission distribution chart\\n\",\n \" - `plot_semantic_alignment()`: Semantic alignment scatter plot\\n\",\n \" - `plot_policy_overlap_bars()`: Policy overlap bar chart\\n\",\n \" - `plot_quality_dashboard()`: Comprehensive dashboard\\n\",\n \"\\n\",\n \"3. **`src/processors/column_level_rbac_generator.py`** - Dataset generation\\n\",\n \" - `ColumnLevelRBACGenerator`: Generate RBAC dataset from role assignments\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \"llm4db\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.10.18\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"}, "2a15af7efb2b5d335e0f468a13312eb587847e2a": {"t": 1785753623.9373732, "n": 427061, "h": "c4e7f848d2377d92", "c": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"id\": \"c4bddd25\",\n \"metadata\": {},\n \"source\": [\n \"## 0. Import and Setup\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 1,\n \"id\": \"93292a4c\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Project root: /home/feiy/Role-SQL-benchmark\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Setup and imports\\n\",\n \"import sys\\n\",\n \"import json\\n\",\n \"import sqlite3\\n\",\n \"from pathlib import Path\\n\",\n \"from pprint import pprint\\n\",\n \"\\n\",\n \"# Add project root to path\\n\",\n \"project_root = Path.cwd().parent\\n\",\n \"sys.path.insert(0, str(project_root))\\n\",\n \"\\n\",\n \"print(f\\\"Project root: {project_root}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 2,\n \"id\": \"bce399e4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Available API keys:\\n\",\n \" OPENAI_API_KEY: ✓\\n\",\n \" DEEPSEEK_API_KEY: ✓\\n\",\n \" DEEPINFRA_API_KEY: ✓\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Load environment and initialize Oracle\\n\",\n \"from dotenv import load_dotenv\\n\",\n \"import os\\n\",\n \"\\n\",\n \"load_dotenv(project_root / '.env')\\n\",\n \"\\n\",\n \"# Check available API keys\\n\",\n \"api_keys = {\\n\",\n \" 'OPENAI_API_KEY': bool(os.getenv('OPENAI_API_KEY')),\\n\",\n \" 'DEEPSEEK_API_KEY': bool(os.getenv('DEEPSEEK_API_KEY')),\\n\",\n \" 'DEEPINFRA_API_KEY': bool(os.getenv('DEEPINFRA_API_KEY')),\\n\",\n \"}\\n\",\n \"print(\\\"Available API keys:\\\")\\n\",\n \"for k, v in api_keys.items():\\n\",\n \" print(f\\\" {k}: {'✓' if v else '✗'}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 3,\n \"id\": \"a4d69b7c\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Using model: deepseek-chat\\n\"\n ]\n },\n {\n \"name\": \"stderr\",\n \"output_type\": \"stream\",\n \"text\": [\n \"/home/feiy/anaconda3/envs/llm4db/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\\n\",\n \" from .autonotebook import tqdm as notebook_tqdm\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Initialize LLM Oracle\\n\",\n \"from src.llm_oracle import Oracle\\n\",\n \"\\n\",\n \"# Choose model based on available keys (prefer DeepSeek for cost efficiency)\\n\",\n \"if os.getenv('DEEPSEEK_API_KEY'):\\n\",\n \" MODEL = \\\"deepseek-chat\\\"\\n\",\n \" API_KEY = os.getenv('DEEPSEEK_API_KEY')\\n\",\n \"elif os.getenv('OPENAI_API_KEY'):\\n\",\n \" MODEL = \\\"gpt-4o-mini\\\"\\n\",\n \" API_KEY = os.getenv('OPENAI_API_KEY')\\n\",\n \"else:\\n\",\n \" raise ValueError(\\\"No API key available!\\\")\\n\",\n \"\\n\",\n \"oracle = Oracle(model=MODEL, apikey=API_KEY)\\n\",\n \"print(f\\\"Using model: {MODEL}\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8809cf55\",\n \"metadata\": {},\n \"source\": [\n \"## 1. Load Sample Database Schema\\n\",\n \"\\n\",\n \"We'll use a BIRD database with interesting column structure for testing.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 4,\n \"id\": \"e9dcc61c\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# Import shared policy utility functions\\n\",\n \"from src.role_evaluator.quality_metrics import RoleQualityEvaluator\\n\",\n \"\\n\",\n \"# Convenience aliases for the static methods\\n\",\n \"count_policy_columns = RoleQualityEvaluator.count_policy_columns\\n\",\n \"has_wildcard_policy = RoleQualityEvaluator.has_wildcard_policy\\n\",\n \"\\n\",\n \"def get_schema_from_sqlite(db_path: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Extract detailed schema from SQLite database.\\\"\\\"\\\"\\n\",\n \" conn = sqlite3.connect(db_path)\\n\",\n \" cursor = conn.cursor()\\n\",\n \" \\n\",\n \" # Get all tables\\n\",\n \" cursor.execute(\\\"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'\\\")\\n\",\n \" tables = [row[0] for row in cursor.fetchall()]\\n\",\n \" \\n\",\n \" schema = {}\\n\",\n \" for table in tables:\\n\",\n \" cursor.execute(f\\\"PRAGMA table_info(`{table}`)\\\")\\n\",\n \" columns = cursor.fetchall()\\n\",\n \" \\n\",\n \" cursor.execute(f\\\"PRAGMA foreign_key_list(`{table}`)\\\")\\n\",\n \" fks = {row[3]: f\\\"{row[2]}.{row[4]}\\\" for row in cursor.fetchall()}\\n\",\n \" \\n\",\n \" schema[table] = {\\n\",\n \" 'columns': [\\n\",\n \" {\\n\",\n \" 'name': col[1],\\n\",\n \" 'type': col[2] or 'TEXT',\\n\",\n \" 'pk': col[5] == 1,\\n\",\n \" 'not_null': col[3] == 1,\\n\",\n \" 'fk': fks.get(col[1])\\n\",\n \" }\\n\",\n \" for col in columns\\n\",\n \" ]\\n\",\n \" }\\n\",\n \" \\n\",\n \" conn.close()\\n\",\n \" return schema\\n\",\n \"\\n\",\n \"def format_schema_for_prompt(schema: dict, db_name: str) -> str:\\n\",\n \" \\\"\\\"\\\"Format schema as text for LLM prompt.\\\"\\\"\\\"\\n\",\n \" lines = [f\\\"Database: {db_name}\\\\n\\\"]\\n\",\n \" \\n\",\n \" for table, info in schema.items():\\n\",\n \" lines.append(f\\\"Table: {table}\\\")\\n\",\n \" lines.append(\\\"Columns:\\\")\\n\",\n \" for col in info['columns']:\\n\",\n \" constraints = []\\n\",\n \" if col['pk']:\\n\",\n \" constraints.append(\\\"PRIMARY KEY\\\")\\n\",\n \" if col['not_null'] and not col['pk']:\\n\",\n \" constraints.append(\\\"NOT NULL\\\")\\n\",\n \" if col['fk']:\\n\",\n \" constraints.append(f\\\"FK -> {col['fk']}\\\")\\n\",\n \" \\n\",\n \" constraint_str = f\\\" [{', '.join(constraints)}]\\\" if constraints else \\\"\\\"\\n\",\n \" lines.append(f\\\" - {col['name']} ({col['type']}){constraint_str}\\\")\\n\",\n \" lines.append(\\\"\\\")\\n\",\n \" \\n\",\n \" return \\\"\\\\n\\\".join(lines)\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 5,\n \"id\": \"705d64b1\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Available BIRD databases (11):\\n\",\n \" - california_schools\\n\",\n \" - card_games\\n\",\n \" - codebase_community\\n\",\n \" - debit_card_specializing\\n\",\n \" - european_football_2\\n\",\n \" - financial\\n\",\n \" - formula_1\\n\",\n \" - student_club\\n\",\n \" - superhero\\n\",\n \" - thrombosis_prediction\\n\",\n \" ...\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Load a sample BIRD database - use the latest 2025 version\\n\",\n \"bird_db_dir = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases'\\n\",\n \"\\n\",\n \"# List available databases\\n\",\n \"available_dbs = [d.name for d in bird_db_dir.iterdir() if d.is_dir()]\\n\",\n \"print(f\\\"Available BIRD databases ({len(available_dbs)}):\\\")\\n\",\n \"for db in sorted(available_dbs)[:10]:\\n\",\n \" print(f\\\" - {db}\\\")\\n\",\n \"print(\\\" ...\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 6,\n \"id\": \"f9e1a86a\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Loading schema from: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev_databases/california_schools/california_schools.sqlite\\n\",\n \"\\n\",\n \"Tables: ['frpm', 'satscores', 'schools']\\n\",\n \"\\n\",\n \"frpm: 29 columns\\n\",\n \" - CDSCode (TEXT)\\n\",\n \" - Academic Year (TEXT)\\n\",\n \" - County Code (TEXT)\\n\",\n \" - District Code (INTEGER)\\n\",\n \" - School Code (TEXT)\\n\",\n \" ... and 24 more\\n\",\n \"\\n\",\n \"satscores: 11 columns\\n\",\n \" - cds (TEXT)\\n\",\n \" - rtype (TEXT)\\n\",\n \" - sname (TEXT)\\n\",\n \" - dname (TEXT)\\n\",\n \" - cname (TEXT)\\n\",\n \" ... and 6 more\\n\",\n \"\\n\",\n \"schools: 49 columns\\n\",\n \" - CDSCode (TEXT)\\n\",\n \" - NCESDist (TEXT)\\n\",\n \" - NCESSchool (TEXT)\\n\",\n \" - StatusType (TEXT)\\n\",\n \" - County (TEXT)\\n\",\n \" ... and 44 more\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Select a database with moderate complexity\\n\",\n \"# 'california_schools' has tables with sensitive-looking columns\\n\",\n \"TEST_DB = \\\"california_schools\\\"\\n\",\n \"db_path = bird_db_dir / TEST_DB / f\\\"{TEST_DB}.sqlite\\\"\\n\",\n \"\\n\",\n \"print(f\\\"Loading schema from: {db_path}\\\")\\n\",\n \"schema = get_schema_from_sqlite(str(db_path))\\n\",\n \"\\n\",\n \"print(f\\\"\\\\nTables: {list(schema.keys())}\\\")\\n\",\n \"for table, info in schema.items():\\n\",\n \" print(f\\\"\\\\n{table}: {len(info['columns'])} columns\\\")\\n\",\n \" for col in info['columns'][:5]:\\n\",\n \" print(f\\\" - {col['name']} ({col['type']})\\\")\\n\",\n \" if len(info['columns']) > 5:\\n\",\n \" print(f\\\" ... and {len(info['columns']) - 5} more\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 7,\n \"id\": \"e5fb0114\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Database: california_schools\\n\",\n \"\\n\",\n \"Table: frpm\\n\",\n \"Columns:\\n\",\n \" - CDSCode (TEXT) [PRIMARY KEY, FK -> schools.CDSCode]\\n\",\n \" - Academic Year (TEXT)\\n\",\n \" - County Code (TEXT)\\n\",\n \" - District Code (INTEGER)\\n\",\n \" - School Code (TEXT)\\n\",\n \" - County Name (TEXT)\\n\",\n \" - District Name (TEXT)\\n\",\n \" - School Name (TEXT)\\n\",\n \" - District Type (TEXT)\\n\",\n \" - School Type (TEXT)\\n\",\n \" - Educational Option Type (TEXT)\\n\",\n \" - NSLP Provision Status (TEXT)\\n\",\n \" - Charter School (Y/N) (INTEGER)\\n\",\n \" - Charter School Number (TEXT)\\n\",\n \" - Charter Funding Type (TEXT)\\n\",\n \" - IRC (INTEGER)\\n\",\n \" - Low Grade (TEXT)\\n\",\n \" - High Grade (TEXT)\\n\",\n \" - Enrollment (K-12) (REAL)\\n\",\n \" - Free Meal Count (K-12) (REAL)\\n\",\n \" - Percent (%) Eligible Free (K-12) (REAL)\\n\",\n \" - FRPM Count (K-12) (REAL)\\n\",\n \" - Percent (%) Eligible FRPM (K-12) (REAL)\\n\",\n \" - Enrollment (Ages 5-17) (REAL)\\n\",\n \" - Free Meal Count (Ages 5-17) (REAL)\\n\",\n \" - Percent (%) Eligible Free (Ages 5-17) (REAL)\\n\",\n \" - FRPM Count (Ages 5-17) (REAL)\\n\",\n \" - Percent (%) Eligible FRPM (Ages 5-17) (REAL)\\n\",\n \" - 2013-14 CALPADS Fall 1 Certification Status (INTEGER)\\n\",\n \"\\n\",\n \"Table: satscores\\n\",\n \"Columns:\\n\",\n \" - cds (TEXT) [PRIMARY KEY, FK -> schools.CDSCode]\\n\",\n \" - rtype (TEXT) [NOT NULL]\\n\",\n \" - sname (TEXT)\\n\",\n \" - dname (TEXT)\\n\",\n \" - cname (TEXT)\\n\",\n \" - enroll12 (INTEGER) [NOT NULL]\\n\",\n \" - NumTstTakr (INTEGER) [NOT NULL]\\n\",\n \" - AvgScrRead (INTEGER)\\n\",\n \" - AvgScrMath (INTEGER)\\n\",\n \" - AvgScrWrite (INTEGER)\\n\",\n \" - NumGE1500 (INTEGER)\\n\",\n \"\\n\",\n \"Table: schools\\n\",\n \"Columns:\\n\",\n \" - CDSCode (TEXT) [PRIMARY KEY]\\n\",\n \" - NCESDist (TEXT)\\n\",\n \" - NCESSchool (TEXT)\\n\",\n \" - StatusType (TEXT) [NOT NULL]\\n\",\n \" - County (TEXT) [NOT NULL]\\n\",\n \" - District (TEXT) [NOT NULL]\\n\",\n \" - School (TEXT)\\n\",\n \" - Street (TEXT)\\n\",\n \" - StreetAbr (TEXT)\\n\",\n \" - City (TEXT)\\n\",\n \" - Zip (TEXT)\\n\",\n \" - State (TEXT)\\n\",\n \" - MailStreet (TEXT)\\n\",\n \" - MailStrAbr (TEXT)\\n\",\n \" - MailCity (TEXT)\\n\",\n \" - MailZip (TEXT)\\n\",\n \" - MailState (TEXT)\\n\",\n \" - Phone (TEXT)\\n\",\n \" - Ext (TEXT)\\n\",\n \" - Website (TEXT)\\n\",\n \" - OpenDate (DATE)\\n\",\n \" - ClosedDate (DATE)\\n\",\n \" - Charter (INTEGER)\\n\",\n \" - CharterNum (TEXT)\\n\",\n \" - FundingType (TEXT)\\n\",\n \" - DOC (TEXT) [NOT NULL]\\n\",\n \" - DOCType (TEXT) [NOT NULL]\\n\",\n \" - SOC (TEXT)\\n\",\n \" - SOCType (TEXT)\\n\",\n \" - EdOpsCode (TEXT)\\n\",\n \" \\n\",\n \"\\n\",\n \"... (total 2401 characters)\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Format schema for prompt\\n\",\n \"schema_text = format_schema_for_prompt(schema, TEST_DB)\\n\",\n \"print(schema_text[:2000])\\n\",\n \"print(f\\\"\\\\n... (total {len(schema_text)} characters)\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8e904509\",\n \"metadata\": {},\n \"source\": [\n \"## 2. Load Prompts from External Modules\\n\",\n \"\\n\",\n \"Prompts are now defined in `configs/column_level_prompts.py`.\\n\",\n \"- **JSON format** is used (more structured, requires max_tokens=4000)\\n\",\n \"- Parser auto-detects format and handles both JSON and Plain Text\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 8,\n \"id\": \"1a425645\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Loaded from external modules:\\n\",\n \" - COLUMN_LEVEL_SYSTEM_PROMPT (2734 chars)\\n\",\n \" - COLUMN_LEVEL_USER_PROMPT_TEMPLATE\\n\",\n \" - DEFAULT_MAX_TOKENS = 4000\\n\",\n \" - parse_column_level_roles (auto-detects JSON/Text)\\n\",\n \" - validate_roles_against_schema\\n\",\n \"\\n\",\n \"--- System Prompt Preview ---\\n\",\n \"You are a database security expert specializing in fine-grained Role-Based Access Control (RBAC).\\n\",\n \"Your job is to read a relational database schema and propose a COHERENT set of roles with COLUMN-LEVEL permissions.\\n\",\n \"\\n\",\n \"Key goals:\\n\",\n \"- Minimize role count while covering real-world workflows (decide number of roles according to real world scenario).\\n\",\n \"- Each role must be clearly related to others (same scenario, complementary duties).\\n\",\n \"- Enforce least-privilege at the COLUMN level (specify which columns eac\\n\",\n \"...\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Reload modules to get latest changes\\n\",\n \"import importlib\\n\",\n \"import configs.column_level_prompts\\n\",\n \"import src.role_parser.column_level_parser\\n\",\n \"importlib.reload(configs.column_level_prompts)\\n\",\n \"importlib.reload(src.role_parser.column_level_parser)\\n\",\n \"\\n\",\n \"# Import prompts and parser from external modules\\n\",\n \"from configs.column_level_prompts import (\\n\",\n \" COLUMN_LEVEL_SYSTEM_PROMPT, \\n\",\n \" COLUMN_LEVEL_USER_PROMPT_TEMPLATE,\\n\",\n \" DEFAULT_MAX_TOKENS\\n\",\n \")\\n\",\n \"from src.role_parser import parse_column_level_roles, validate_roles_against_schema\\n\",\n \"\\n\",\n \"print(\\\"✓ Loaded from external modules:\\\")\\n\",\n \"print(f\\\" - COLUMN_LEVEL_SYSTEM_PROMPT ({len(COLUMN_LEVEL_SYSTEM_PROMPT)} chars)\\\")\\n\",\n \"print(f\\\" - COLUMN_LEVEL_USER_PROMPT_TEMPLATE\\\")\\n\",\n \"print(f\\\" - DEFAULT_MAX_TOKENS = {DEFAULT_MAX_TOKENS}\\\")\\n\",\n \"print(f\\\" - parse_column_level_roles (auto-detects JSON/Text)\\\")\\n\",\n \"print(f\\\" - validate_roles_against_schema\\\")\\n\",\n \"\\n\",\n \"print(\\\"\\\\n--- System Prompt Preview ---\\\")\\n\",\n \"print(COLUMN_LEVEL_SYSTEM_PROMPT[:500])\\n\",\n \"print(\\\"...\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"0acacb6e\",\n \"metadata\": {},\n \"source\": [\n \"## [Archived] Single-Sample Experiments\\n\",\n \"\\n\",\n \"以下代码块包含单样本测试代码,用于调试 prompt 和 parser。\\n\",\n \"**已注释,正式运行请跳过此节,直接执行第8节批量处理。**\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 9,\n \"id\": \"e9700ae1\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"⏭️ 此cell已注释,跳过单样本实验,请直接运行第8节批量处理\\n\"\n ]\n }\n ],\n \"source\": [\n \"# ============================================================\\n\",\n \"# [ARCHIVED] 单样本实验代码 - 已注释,跳过此cell\\n\",\n \"# ============================================================\\n\",\n \"# 以下代码用于单个数据库 (california_schools) 的测试和调试\\n\",\n \"# 正式运行请直接跳到第8节批量处理\\n\",\n \"\\n\",\n \"'''\\n\",\n \"# --- 3. Generate Column-Level Roles (Single DB) ---\\n\",\n \"print(\\\"Generating column-level roles...\\\")\\n\",\n \"user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=schema_text)\\n\",\n \"response = oracle.query(\\n\",\n \" prompt_sys=COLUMN_LEVEL_SYSTEM_PROMPT,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3, top_p=0.9,\\n\",\n \" max_completion_tokens=DEFAULT_MAX_TOKENS\\n\",\n \")\\n\",\n \"llm_response = response['answer']\\n\",\n \"print(f\\\"Response length: {len(llm_response)} chars\\\")\\n\",\n \"\\n\",\n \"# --- 4. Parse and Validate ---\\n\",\n \"from src.role_parser.column_level_parser import parse_column_level_roles\\n\",\n \"parsed_roles = parse_column_level_roles(llm_response)\\n\",\n \"print(f\\\"Parsed {len(parsed_roles)} roles\\\")\\n\",\n \"\\n\",\n \"validation = validate_roles_against_schema(parsed_roles, str(db_path))\\n\",\n \"print(f\\\"Valid: {validation['valid_roles']}/{validation['total_roles']}\\\")\\n\",\n \"\\n\",\n \"# --- 5. Show Results ---\\n\",\n \"for role in parsed_roles:\\n\",\n \" print(f\\\" - {role['role']}: {len(role.get('columns', {}))} tables\\\")\\n\",\n \"\\n\",\n \"# --- 6. Compare with Table-Level ---\\n\",\n \"from configs.prompts import SYSTEM_PROMPT as TABLE_LEVEL_PROMPT, USER_PROMPT_TEMPLATE\\n\",\n \"table_level_response = oracle.query(\\n\",\n \" prompt_sys=TABLE_LEVEL_PROMPT,\\n\",\n \" prompt_user=USER_PROMPT_TEMPLATE.format(schema_content=schema_text),\\n\",\n \" temp=0.3, top_p=0.9\\n\",\n \")\\n\",\n \"print(\\\"Table-Level Response:\\\", table_level_response['answer'][:500])\\n\",\n \"\\n\",\n \"# --- 7. Save Single DB Result ---\\n\",\n \"def convert_to_assignment_format(parsed_roles, db_name):\\n\",\n \" return {\\\"assignments\\\": {db_name: [\\n\",\n \" {\\\"role\\\": r[\\\"role\\\"], \\\"description\\\": r.get(\\\"description\\\", \\\"\\\"), \\\"policy\\\": r.get(\\\"columns\\\", {})}\\n\",\n \" for r in parsed_roles\\n\",\n \" ]}}\\n\",\n \"\\n\",\n \"column_level_assignments = convert_to_assignment_format(parsed_roles, TEST_DB)\\n\",\n \"output_file = project_root / 'outputs' / 'column_level_role_assignments.json'\\n\",\n \"with open(output_file, 'w') as f:\\n\",\n \" json.dump(column_level_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \"print(f\\\"Saved to: {output_file}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ 此cell已注释,跳过单样本实验,请直接运行第8节批量处理\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8bc8cb95\",\n \"metadata\": {},\n \"source\": [\n \"## 3. Batch Process All BIRD Databases\\n\",\n \"\\n\",\n \"Generate column-level role assignments for all BIRD databases with parallel processing.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 10,\n \"id\": \"fe3f2e81\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Configuration:\\n\",\n \" Workers: 40\\n\",\n \" Databases: 11\\n\",\n \" Max tokens: 4000\\n\",\n \" Model: deepseek-chat\\n\",\n \"\\n\",\n \"Databases to process:\\n\",\n \" - superhero\\n\",\n \" - thrombosis_prediction\\n\",\n \" - student_club\\n\",\n \" - toxicology\\n\",\n \" - california_schools\\n\",\n \" - debit_card_specializing\\n\",\n \" - card_games\\n\",\n \" - codebase_community\\n\",\n \" - formula_1\\n\",\n \" - european_football_2\\n\",\n \" - financial\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Batch processing configuration\\n\",\n \"from concurrent.futures import ThreadPoolExecutor, as_completed\\n\",\n \"from tqdm.notebook import tqdm\\n\",\n \"\\n\",\n \"# Configuration\\n\",\n \"WORKERS = 40\\n\",\n \"SAMPLES = 100 # 0 for all databases\\n\",\n \"MAX_TOKENS = DEFAULT_MAX_TOKENS\\n\",\n \"\\n\",\n \"# Get all BIRD databases\\n\",\n \"all_dbs = [d.name for d in bird_db_dir.iterdir() if d.is_dir()]\\n\",\n \"if SAMPLES > 0:\\n\",\n \" all_dbs = all_dbs[:SAMPLES]\\n\",\n \"\\n\",\n \"print(f\\\"Configuration:\\\")\\n\",\n \"print(f\\\" Workers: {WORKERS}\\\")\\n\",\n \"print(f\\\" Databases: {len(all_dbs)}\\\")\\n\",\n \"print(f\\\" Max tokens: {MAX_TOKENS}\\\")\\n\",\n \"print(f\\\" Model: {MODEL}\\\")\\n\",\n \"print(f\\\"\\\\nDatabases to process:\\\")\\n\",\n \"for db in all_dbs:\\n\",\n \" print(f\\\" - {db}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 11,\n \"id\": \"7b5edd94\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Helper functions defined\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Helper functions for batch processing\\n\",\n \"\\n\",\n \"def process_single_database(db_name: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Process a single database and return role assignments.\\\"\\\"\\\"\\n\",\n \" db_path = bird_db_dir / db_name / f\\\"{db_name}.sqlite\\\"\\n\",\n \" \\n\",\n \" if not db_path.exists():\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": f\\\"Database not found\\\"}\\n\",\n \" \\n\",\n \" try:\\n\",\n \" # Extract schema\\n\",\n \" db_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" db_schema_text = format_schema_for_prompt(db_schema, db_name)\\n\",\n \" \\n\",\n \" # Generate roles via LLM\\n\",\n \" user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=db_schema_text)\\n\",\n \" \\n\",\n \" response = oracle.query(\\n\",\n \" prompt_sys=COLUMN_LEVEL_SYSTEM_PROMPT,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3,\\n\",\n \" top_p=0.9,\\n\",\n \" max_completion_tokens=MAX_TOKENS\\n\",\n \" )\\n\",\n \" \\n\",\n \" llm_response = response['answer']\\n\",\n \" usage = response.get('usage', {})\\n\",\n \" \\n\",\n \" # Parse response\\n\",\n \" roles = parse_column_level_roles(llm_response)\\n\",\n \" \\n\",\n \" if not roles:\\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"parse_error\\\",\\n\",\n \" \\\"error\\\": \\\"Failed to parse LLM response\\\",\\n\",\n \" \\\"raw_response\\\": llm_response[:300]\\n\",\n \" }\\n\",\n \" \\n\",\n \" # Validate against schema\\n\",\n \" validation = validate_roles_against_schema(roles, str(db_path))\\n\",\n \" \\n\",\n \" # Convert to target format\\n\",\n \" assignments = []\\n\",\n \" for role in roles:\\n\",\n \" assignments.append({\\n\",\n \" \\\"role\\\": role[\\\"role\\\"],\\n\",\n \" \\\"description\\\": role.get(\\\"description\\\", \\\"\\\"),\\n\",\n \" \\\"policy\\\": role.get(\\\"columns\\\", {})\\n\",\n \" })\\n\",\n \" \\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"success\\\",\\n\",\n \" \\\"roles_count\\\": len(assignments),\\n\",\n \" \\\"valid_roles\\\": validation['valid_roles'],\\n\",\n \" \\\"all_valid\\\": validation['all_valid'],\\n\",\n \" \\\"assignments\\\": assignments,\\n\",\n \" \\\"usage\\\": usage\\n\",\n \" }\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" return {\\n\",\n \" \\\"database\\\": db_name,\\n\",\n \" \\\"status\\\": \\\"error\\\",\\n\",\n \" \\\"error\\\": str(e)\\n\",\n \" }\\n\",\n \"\\n\",\n \"print(\\\"✓ Helper functions defined\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 12,\n \"id\": \"61e61795\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Starting batch processing with 40 workers...\\n\",\n \"============================================================\\n\",\n \"[1/11] ✓ toxicology: 4 roles (4 valid)\\n\",\n \"[2/11] ✓ debit_card_specializing: 4 roles (4 valid)\\n\",\n \"[3/11] ✓ thrombosis_prediction: 4 roles (4 valid)\\n\",\n \"[4/11] ✓ student_club: 5 roles (5 valid)\\n\",\n \"[5/11] ✓ superhero: 5 roles (5 valid)\\n\",\n \"[6/11] ✓ financial: 5 roles (5 valid)\\n\",\n \"[7/11] ✓ card_games: 5 roles (5 valid)\\n\",\n \"[8/11] ✓ codebase_community: 4 roles (4 valid)\\n\",\n \"[9/11] ✓ california_schools: 5 roles (5 valid)\\n\",\n \"[10/11] ✓ formula_1: 5 roles (5 valid)\\n\",\n \"[11/11] ✓ european_football_2: 5 roles (5 valid)\\n\",\n \"============================================================\\n\",\n \"Completed: 11/11 success, 0 errors\\n\",\n \"Total tokens: 25,679\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Execute batch processing with parallel workers\\n\",\n \"print(f\\\"Starting batch processing with {WORKERS} workers...\\\")\\n\",\n \"print(\\\"=\\\" * 60)\\n\",\n \"\\n\",\n \"results = {\\n\",\n \" \\\"metadata\\\": {\\n\",\n \" \\\"model\\\": MODEL,\\n\",\n \" \\\"max_tokens\\\": MAX_TOKENS,\\n\",\n \" \\\"total_databases\\\": len(all_dbs)\\n\",\n \" },\\n\",\n \" \\\"assignments\\\": {},\\n\",\n \" \\\"errors\\\": []\\n\",\n \"}\\n\",\n \"\\n\",\n \"success_count = 0\\n\",\n \"error_count = 0\\n\",\n \"total_tokens = {\\\"prompt\\\": 0, \\\"completion\\\": 0}\\n\",\n \"\\n\",\n \"with ThreadPoolExecutor(max_workers=WORKERS) as executor:\\n\",\n \" futures = {executor.submit(process_single_database, db): db for db in all_dbs}\\n\",\n \" \\n\",\n \" for i, future in enumerate(as_completed(futures), 1):\\n\",\n \" db_name = futures[future]\\n\",\n \" try:\\n\",\n \" result = future.result()\\n\",\n \" \\n\",\n \" if result[\\\"status\\\"] == \\\"success\\\":\\n\",\n \" results[\\\"assignments\\\"][result[\\\"database\\\"]] = result[\\\"assignments\\\"]\\n\",\n \" success_count += 1\\n\",\n \" \\n\",\n \" usage = result.get(\\\"usage\\\", {})\\n\",\n \" total_tokens[\\\"prompt\\\"] += usage.get(\\\"prompt_tokens\\\", 0)\\n\",\n \" total_tokens[\\\"completion\\\"] += usage.get(\\\"completion_tokens\\\", 0)\\n\",\n \" \\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✓ {db_name}: {result['roles_count']} roles ({result['valid_roles']} valid)\\\")\\n\",\n \" else:\\n\",\n \" results[\\\"errors\\\"].append(result)\\n\",\n \" error_count += 1\\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✗ {db_name}: {result.get('error', result['status'])}\\\")\\n\",\n \" \\n\",\n \" except Exception as e:\\n\",\n \" error_count += 1\\n\",\n \" results[\\\"errors\\\"].append({\\\"database\\\": db_name, \\\"error\\\": str(e)})\\n\",\n \" print(f\\\"[{i}/{len(all_dbs)}] ✗ {db_name}: {e}\\\")\\n\",\n \"\\n\",\n \"results[\\\"metadata\\\"][\\\"success_count\\\"] = success_count\\n\",\n \"results[\\\"metadata\\\"][\\\"error_count\\\"] = error_count\\n\",\n \"results[\\\"metadata\\\"][\\\"total_tokens\\\"] = total_tokens\\n\",\n \"\\n\",\n \"print(\\\"=\\\" * 60)\\n\",\n \"print(f\\\"Completed: {success_count}/{len(all_dbs)} success, {error_count} errors\\\")\\n\",\n \"print(f\\\"Total tokens: {total_tokens['prompt'] + total_tokens['completion']:,}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 13,\n \"id\": \"39d38aa3\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"✓ Results saved to: /home/feiy/Role-SQL-benchmark/outputs/column_level_role_assignments_bird.json\\n\",\n \"\\n\",\n \"File structure:\\n\",\n \" - metadata: model, tokens, counts\\n\",\n \" - assignments: 11 databases\\n\",\n \" - errors: 0 entries\\n\",\n \"\\n\",\n \"Sample (toxicology):\\n\",\n \"[\\n\",\n \" {\\n\",\n \" \\\"role\\\": \\\"MolecularResearcher\\\",\\n\",\n \" \\\"description\\\": \\\"Analyzes molecular structures and their components for research purposes\\\",\\n\",\n \" \\\"policy\\\": {\\n\",\n \" \\\"molecule\\\": [\\n\",\n \" \\\"molecule_id\\\",\\n\",\n \" \\\"label\\\"\\n\",\n \" ],\\n\",\n \" \\\"atom\\\": [\\n\",\n \" \\\"atom_id\\\",\\n\",\n \" \\\"molecule_id\\\",\\n\",\n \" \\\"element\\\"\\n\",\n \" ],\\n\",\n \" \\\"bond\\\": [\\n\",\n \" \\\"bond_id\\\",\\n\",\n \" \\\"molecule_id\\\",\\n\",\n \" \\\"bond_type\\\"\\n\",\n \" ],\\n\",\n \" \\\"connected\\\": [\\n\",\n \" \\\"atom_id\\\",\\n\",\n \" \\\"atom_id2\\\",\\n\",\n \" \\\"bond_id\\\"\\n\",\n \" ]\\n\",\n \" }\\n\",\n \" }\\n\",\n \"]\\n\"\n ]\n }\n ],\n \"source\": [\n \"# Save batch results to file\\n\",\n \"output_file = project_root / 'outputs' / 'column_level_role_assignments_bird.json'\\n\",\n \"\\n\",\n \"with open(output_file, 'w', encoding='utf-8') as f:\\n\",\n \" json.dump(results, f, indent=2, ensure_ascii=False)\\n\",\n \"\\n\",\n \"print(f\\\"✓ Results saved to: {output_file}\\\")\\n\",\n \"print(f\\\"\\\\nFile structure:\\\")\\n\",\n \"print(f\\\" - metadata: model, tokens, counts\\\")\\n\",\n \"print(f\\\" - assignments: {len(results['assignments'])} databases\\\")\\n\",\n \"print(f\\\" - errors: {len(results['errors'])} entries\\\")\\n\",\n \"\\n\",\n \"# Show sample\\n\",\n \"if results['assignments']:\\n\",\n \" sample_db = list(results['assignments'].keys())[0]\\n\",\n \" print(f\\\"\\\\nSample ({sample_db}):\\\")\\n\",\n \" print(json.dumps(results['assignments'][sample_db][:1], indent=2, ensure_ascii=False)[:500])\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"9595c46d\",\n \"metadata\": {},\n \"source\": [\n \"## 4. Generate Column-Level RBAC Dataset\\n\",\n \"\\n\",\n \"Based on the generated role policies, combined with BIRD dataset queries, generate the final RBAC training/evaluation dataset.\\n\",\n \"\\n\",\n \"Dataset format (consistent with table-level):\\n\",\n \"- `db_id`: Database name\\n\",\n \"- `instruction`: Full instruction with schema + evidence + role policy\\n\",\n \"- `role`: Role name\\n\",\n \"- `policy`: Column-level permission policy {table: [columns]}\\n\",\n \"- `input`: User question\\n\",\n \"- `output`: SQL or denial message\\n\",\n \"- `difficulty`: Query difficulty level\\n\",\n \"- `metadata`: Contains gold_sql, permission, query_columns, missing_columns, etc.\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 45,\n \"id\": \"405783fa\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Dataset Generation Config ===\\n\",\n \"Role assignments: /home/feiy/Role-SQL-benchmark/outputs/column_level_role_assignments_bird.json\\n\",\n \"BIRD data file: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev.json\\n\",\n \"BIRD database dir: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev_databases\\n\",\n \"\\n\",\n \"✓ All file paths are valid\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 4.1 Import generator and test dependencies\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator, format_policy_text\\n\",\n \"from src.processors.column_extractor import extract_query_columns\\n\",\n \"from src.processors.column_permission_checker import check_column_permission\\n\",\n \"import glob\\n\",\n \"\\n\",\n \"# Configure paths - use 2025 version (dev_20251106) for latest BIRD data\\n\",\n \"ROLE_ASSIGNMENTS_PATH = project_root / 'outputs' / 'column_level_role_assignments_bird.json'\\n\",\n \"BIRD_DATA_PATH = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev.json'\\n\",\n \"BIRD_DB_ROOT = project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases'\\n\",\n \"\\n\",\n \"print(\\\"=== Dataset Generation Config ===\\\")\\n\",\n \"print(f\\\"Role assignments: {ROLE_ASSIGNMENTS_PATH}\\\")\\n\",\n \"print(f\\\"BIRD data file: {BIRD_DATA_PATH}\\\")\\n\",\n \"print(f\\\"BIRD database dir: {BIRD_DB_ROOT}\\\")\\n\",\n \"\\n\",\n \"# Verify file existence\\n\",\n \"# assert ROLE_ASSIGNMENTS_PATH.exists(), f\\\"Role assignments file not found: {ROLE_ASSIGNMENTS_PATH}\\\"\\n\",\n \"assert BIRD_DATA_PATH.exists(), f\\\"BIRD data file not found: {BIRD_DATA_PATH}\\\"\\n\",\n \"assert BIRD_DB_ROOT.exists(), f\\\"BIRD database dir not found: {BIRD_DB_ROOT}\\\"\\n\",\n \"print(\\\"\\\\n✓ All file paths are valid\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4b80dc65\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== SQL Column Extraction Test ===\\n\",\n \"Tables: {'song', 'singer'}\\n\",\n \"Columns: {'song': {'singer_id', 'title'}, 'singer': {'id', 'name', 'country', 'age'}}\\n\",\n \"Has *: False\\n\",\n \"\\n\",\n \"=== Permission Check Test (Allow) ===\\n\",\n \"Allowed: True\\n\",\n \"Reason: All required columns are permitted\\n\",\n \"\\n\",\n \"=== Permission Check Test (Deny) ===\\n\",\n \"Allowed: False\\n\",\n \"Reason: Missing column permissions: song: singer_id; singer: age, country, id\\n\",\n \"Missing: {'song': {'singer_id'}, 'singer': {'id', 'country', 'age'}}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.2 Test SQL column extraction and permission checking\\n\",\n \"# 已验证工作正常,archive 以简化 notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"test_sql = \\\"\\\"\\\"\\n\",\n \"SELECT singer.name, singer.age, song.title\\n\",\n \"FROM singer\\n\",\n \"JOIN song ON singer.id = song.singer_id\\n\",\n \"WHERE singer.country = 'USA'\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"print(\\\"=== SQL Column Extraction Test ===\\\")\\n\",\n \"info = extract_query_columns(test_sql)\\n\",\n \"print(f\\\"Tables: {info.tables}\\\")\\n\",\n \"print(f\\\"Columns: {info.columns}\\\")\\n\",\n \"print(f\\\"Has *: {info.has_star}\\\")\\n\",\n \"\\n\",\n \"# Test permission checking\\n\",\n \"policy_allow = {\\n\",\n \" 'singer': ['name', 'age', 'country', 'id'],\\n\",\n \" 'song': ['title', 'singer_id']\\n\",\n \"}\\n\",\n \"policy_deny = {\\n\",\n \" 'singer': ['name'], # Missing 'age', 'country', 'id'\\n\",\n \" 'song': ['title'] # Missing 'singer_id'\\n\",\n \"}\\n\",\n \"\\n\",\n \"print(\\\"\\\\n=== Permission Check Test (Allow) ===\\\")\\n\",\n \"result1 = check_column_permission(test_sql, policy_allow)\\n\",\n \"print(f\\\"Allowed: {result1.allowed}\\\")\\n\",\n \"print(f\\\"Reason: {result1.reason}\\\")\\n\",\n \"\\n\",\n \"print(\\\"\\\\n=== Permission Check Test (Deny) ===\\\")\\n\",\n \"result2 = check_column_permission(test_sql, policy_deny)\\n\",\n \"print(f\\\"Allowed: {result2.allowed}\\\")\\n\",\n \"print(f\\\"Reason: {result2.reason}\\\")\\n\",\n \"print(f\\\"Missing: {result2.missing_columns}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Column extraction/permission tests - 已验证正常\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 16,\n \"id\": \"0a018208\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Generator Initialized ===\\n\",\n \"Total BIRD queries: 1534\\n\",\n \"Databases with role assignments: 11\\n\",\n \"Databases with queries: 11\\n\",\n \"\\n\",\n \"Queries per database:\\n\",\n \" california_schools: 89\\n\",\n \" card_games: 191\\n\",\n \" codebase_community: 186\\n\",\n \" debit_card_specializing: 64\\n\",\n \" european_football_2: 129\\n\",\n \" financial: 106\\n\",\n \" formula_1: 174\\n\",\n \" student_club: 158\\n\",\n \" superhero: 129\\n\",\n \" thrombosis_prediction: 163\\n\",\n \" toxicology: 145\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 4.3 Initialize generator\\n\",\n \"generator = ColumnLevelRBACGenerator(\\n\",\n \" role_assignments_path=str(ROLE_ASSIGNMENTS_PATH),\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH),\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" project_root=str(project_root),\\n\",\n \" seed=42\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"=== Generator Initialized ===\\\")\\n\",\n \"print(f\\\"Total BIRD queries: {len(generator.bird_data)}\\\")\\n\",\n \"print(f\\\"Databases with role assignments: {len(generator.role_assignments.get('assignments', {}))}\\\")\\n\",\n \"print(f\\\"Databases with queries: {len(generator.queries_by_db)}\\\")\\n\",\n \"\\n\",\n \"# Show query counts per database\\n\",\n \"print(\\\"\\\\nQueries per database:\\\")\\n\",\n \"for db_id, queries in sorted(generator.queries_by_db.items()):\\n\",\n \" print(f\\\" {db_id}: {len(queries)}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"2a267246\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Generating Sample Dataset ===\\n\",\n \"Generating column-level RBAC dataset...\\n\",\n \" Roles per DB: 1\\n\",\n \" Queries per role: 3\\n\",\n \"Current ratio (allowed): 60.61%\\n\",\n \" Allowed: 20, Denied: 13\\n\",\n \"\\n\",\n \"Dataset saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_sample.json\\n\",\n \"Metadata saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_sample_metadata.json\\n\",\n \" Total entries: 33\\n\",\n \" Allowed: 20 (60.6%)\\n\",\n \" Denied: 13 (39.4%)\\n\",\n \"\\n\",\n \"Statistics:\\n\",\n \" total_entries: 33\\n\",\n \" allowed: 20\\n\",\n \" denied: 13\\n\",\n \" allowed_ratio: 0.6060606060606061\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.4 Generate sample dataset (for format validation)\\n\",\n \"# Sample 数据集已用于调试,正式生成使用 4.5\\n\",\n \"\\n\",\n \"'''\\n\",\n \"print(\\\"=== Generating Sample Dataset ===\\\")\\n\",\n \"sample_stats = generator.generate_and_save(\\n\",\n \" output_path=str(project_root / 'outputs' / 'column_level_rbac_dataset_bird_sample.json'),\\n\",\n \" roles_per_db=1, # Use only 1 role per database\\n\",\n \" queries_per_role=3 # Use only 3 queries per role\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"\\\\\\\\nStatistics:\\\")\\n\",\n \"for k, v in sample_stats.items():\\n\",\n \" if k != 'by_database':\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Sample dataset generation - 正式生成使用 4.5\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"4851fde0\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Data Format Validation ===\\n\",\n \"Total entries: 33\\n\",\n \"\\n\",\n \"--- Allowed Entry Example ---\\n\",\n \"db_id: toxicology\\n\",\n \"role: MolecularResearcher\\n\",\n \"policy: {\\\"molecule\\\": [\\\"molecule_id\\\", \\\"label\\\"], \\\"atom\\\": [\\\"atom_id\\\", \\\"molecule_id\\\", \\\"element\\\"], \\\"bond\\\": [\\\"bond...\\n\",\n \"input: What are the atom IDs of the bond TR000_2_5?...\\n\",\n \"output: SELECT T.atom_id FROM connected AS T WHERE T.bond_id = 'TR000_2_5'...\\n\",\n \"difficulty: simple\\n\",\n \"instruction length: 1887 chars\\n\",\n \"\\n\",\n \"--- Denied Entry Example ---\\n\",\n \"db_id: thrombosis_prediction\\n\",\n \"role: ClinicalResearcher\\n\",\n \"input: How old was the patient who had the highest hemoglobin count on the date of labo...\\n\",\n \"output: Sorry, I cannot answer.\\n\",\n \"missing_columns: {'patient': ['Diagnosis']}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.5-4.6 Validate generated data format & Show instruction example\\n\",\n \"# 已验证数据格式正确,archive 以简化 notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"sample_file = project_root / 'outputs' / 'column_level_rbac_dataset_bird_sample.json'\\n\",\n \"with open(sample_file, 'r') as f:\\n\",\n \" sample_data = json.load(f)\\n\",\n \"\\n\",\n \"print(\\\"=== Data Format Validation ===\\\")\\n\",\n \"print(f\\\"Total entries: {len(sample_data)}\\\")\\n\",\n \"\\n\",\n \"allowed_entry = next((e for e in sample_data if e['metadata']['permission'] == 'allowed'), None)\\n\",\n \"denied_entry = next((e for e in sample_data if e['metadata']['permission'] == 'denied'), None)\\n\",\n \"\\n\",\n \"if allowed_entry:\\n\",\n \" print(\\\"\\\\\\\\n--- Allowed Entry Example ---\\\")\\n\",\n \" print(f\\\"db_id: {allowed_entry['db_id']}\\\")\\n\",\n \" print(f\\\"role: {allowed_entry['role']}\\\")\\n\",\n \" print(f\\\"policy: {json.dumps(allowed_entry['policy'])[:100]}...\\\")\\n\",\n \" print(f\\\"input: {allowed_entry['input'][:80]}...\\\")\\n\",\n \" print(f\\\"output: {allowed_entry['output'][:80]}...\\\")\\n\",\n \"\\n\",\n \"if denied_entry:\\n\",\n \" print(\\\"\\\\\\\\n--- Denied Entry Example ---\\\")\\n\",\n \" print(f\\\"db_id: {denied_entry['db_id']}\\\")\\n\",\n \" print(f\\\"role: {denied_entry['role']}\\\")\\n\",\n \" print(f\\\"output: {denied_entry['output']}\\\")\\n\",\n \" print(f\\\"missing_columns: {denied_entry['metadata']['missing_columns']}\\\")\\n\",\n \"\\n\",\n \"# Show full instruction\\n\",\n \"print(\\\"\\\\\\\\n=== Full Instruction Example ===\\\")\\n\",\n \"if allowed_entry:\\n\",\n \" print(allowed_entry['instruction'][:2500])\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Data format validation - 已验证正常\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"c05e8787\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Generating Full Column-Level RBAC Dataset ===\\n\",\n \"Output: /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251224.json\\n\",\n \"Note: Using updated column_extractor with CTE fix\\n\",\n \"Generating column-level RBAC dataset...\\n\",\n \" Roles per DB: None\\n\",\n \" Queries per role: all\\n\",\n \"Current ratio (allowed): 61.18%\\n\",\n \" Allowed: 4351, Denied: 2761\\n\",\n \"\\n\",\n \"Dataset saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251224.json\\n\",\n \"Metadata saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251224_metadata.json\\n\",\n \" Total entries: 7112\\n\",\n \" Allowed: 4351 (61.2%)\\n\",\n \" Denied: 2761 (38.8%)\\n\",\n \"\\n\",\n \"Full dataset statistics:\\n\",\n \" total_entries: 7112\\n\",\n \" allowed: 4351\\n\",\n \" denied: 2761\\n\",\n \" allowed_ratio: 0.6117829021372329\\n\",\n \"\\n\",\n \"Per-database distribution:\\n\",\n \" toxicology: allowed=580, denied=0\\n\",\n \" debit_card_specializing: allowed=223, denied=33\\n\",\n \" thrombosis_prediction: allowed=432, denied=220\\n\",\n \" student_club: allowed=396, denied=394\\n\",\n \" superhero: allowed=328, denied=317\\n\",\n \" financial: allowed=212, denied=318\\n\",\n \" card_games: allowed=507, denied=448\\n\",\n \" codebase_community: allowed=669, denied=75\\n\",\n \" california_schools: allowed=173, denied=272\\n\",\n \" formula_1: allowed=553, denied=317\\n\",\n \" european_football_2: allowed=278, denied=367\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 4.5 Generate Full Column-Level RBAC Dataset\\n\",\n \"from datetime import datetime\\n\",\n \"\\n\",\n \"# Reload the modules to ensure we use the latest CTE fix\\n\",\n \"import importlib\\n\",\n \"import src.processors.column_extractor\\n\",\n \"import src.processors.column_permission_checker\\n\",\n \"import src.processors.column_level_rbac_generator\\n\",\n \"\\n\",\n \"importlib.reload(src.processors.column_extractor)\\n\",\n \"importlib.reload(src.processors.column_permission_checker)\\n\",\n \"importlib.reload(src.processors.column_level_rbac_generator)\\n\",\n \"\\n\",\n \"# Re-import with fresh code\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator\\n\",\n \"\\n\",\n \"# Re-create generator with fresh modules\\n\",\n \"generator = ColumnLevelRBACGenerator(\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" role_assignments_path=str(ROLE_ASSIGNMENTS_PATH),\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH)\\n\",\n \")\\n\",\n \"\\n\",\n \"# Output with date suffix\\n\",\n \"today = datetime.now().strftime('%Y%m%d')\\n\",\n \"output_path = project_root / 'outputs' / f'column_level_rbac_dataset_bird_{today}.json'\\n\",\n \"\\n\",\n \"print(\\\"=== Generating Full Column-Level RBAC Dataset ===\\\")\\n\",\n \"print(f\\\"Output: {output_path}\\\")\\n\",\n \"\\n\",\n \"full_stats = generator.generate_and_save(\\n\",\n \" output_path=str(output_path),\\n\",\n \" roles_per_db=None, # Use all roles (number varies per db based on LLM generation)\\n\",\n \" queries_per_role=None # Use all queries\\n\",\n \")\\n\",\n \"\\n\",\n \"print(\\\"\\\\nFull dataset statistics:\\\")\\n\",\n \"for k, v in full_stats.items():\\n\",\n \" if k == 'by_database':\\n\",\n \" print(f\\\"\\\\nPer-database distribution:\\\")\\n\",\n \" for db_id, counts in v.items():\\n\",\n \" print(f\\\" {db_id}: allowed={counts['allowed']}, denied={counts['denied']}\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" {k}: {v}\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": null,\n \"id\": \"2142ac6e\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Comparison with Table-Level Data Format ===\\n\",\n \"\\n\",\n \"--- Table-Level Entry Fields ---\\n\",\n \"['db_id', 'difficulty', 'input', 'instruction', 'metadata', 'output', 'role', 'tables']\\n\",\n \"\\n\",\n \"--- Column-Level Entry Fields ---\\n\",\n \"['db_id', 'difficulty', 'input', 'instruction', 'metadata', 'output', 'policy', 'role']\\n\",\n \"\\n\",\n \"Common fields: {'output', 'role', 'metadata', 'difficulty', 'db_id', 'input', 'instruction'}\\n\",\n \"Table-Level only: {'tables'}\\n\",\n \"Column-Level only: {'policy'}\\n\"\n ]\n }\n ],\n \"source\": [\n \"# [ARCHIVED] 4.6 Compare with Table-Level format\\n\",\n \"# 格式对比已完成,archive 以简化 notebook\\n\",\n \"\\n\",\n \"'''\\n\",\n \"print(\\\"=== Comparison with Table-Level Data Format ===\\\")\\n\",\n \"\\n\",\n \"table_level_file = project_root / 'data' / 'selected' / 'bird' / 'bird_dev_with_role_rbac.json'\\n\",\n \"if table_level_file.exists():\\n\",\n \" with open(table_level_file, 'r') as f:\\n\",\n \" table_level_data = json.load(f)\\n\",\n \" \\n\",\n \" print(\\\"\\\\\\\\n--- Table-Level Entry Fields ---\\\")\\n\",\n \" print(sorted(table_level_data[0].keys()))\\n\",\n \" \\n\",\n \" print(\\\"\\\\\\\\n--- Column-Level Entry Fields ---\\\") \\n\",\n \" print(sorted(sample_data[0].keys()))\\n\",\n \" \\n\",\n \" tl_keys = set(table_level_data[0].keys())\\n\",\n \" cl_keys = set(sample_data[0].keys())\\n\",\n \" \\n\",\n \" print(f\\\"\\\\\\\\nCommon fields: {tl_keys & cl_keys}\\\")\\n\",\n \" print(f\\\"Table-Level only: {tl_keys - cl_keys}\\\")\\n\",\n \" print(f\\\"Column-Level only: {cl_keys - tl_keys}\\\")\\n\",\n \"'''\\n\",\n \"\\n\",\n \"print(\\\"⏭️ [ARCHIVED] Table-level comparison - 格式已验证兼容\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"7392ebc1\",\n \"metadata\": {},\n \"source\": [\n \"## 5. Role Generation Quality Assessment\\n\",\n \"\\n\",\n \"Automated quality checks for generated role files and RBAC datasets.\\n\",\n \"\\n\",\n \"### Quality Metrics\\n\",\n \"\\n\",\n \"| Metric | Healthy Range | Issue Description |\\n\",\n \"|--------|---------------|-------------------|\\n\",\n \"| **Deny Rate** | 5% - 90% | <5% too permissive, >90% too restrictive |\\n\",\n \"| **All-Allow Queries** | <50% | High value indicates poor role differentiation |\\n\",\n \"| **Role-Schema Similarity** | >0.6 | <0.6 indicates poor semantic alignment |\\n\",\n \"| **Policy Overlap** | <70% | >70% indicates redundant roles |\\n\",\n \"| **Coverage Diversity** | std >0.1 | Low std indicates roles have similar permissions |\\n\",\n \"\\n\",\n \"### Evaluation Pipeline\\n\",\n \"1. **Deny Rate Analysis**: Check permission distribution balance\\n\",\n \"2. **Semantic Quality**: Embedding-based role-schema alignment\\n\",\n \"3. **Policy Overlap**: Jaccard similarity to detect redundant roles\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 73,\n \"id\": \"71f8f60f\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Quality Thresholds (Configurable for BIRD) ===\\n\",\n \" deny_rate_min: 5.0\\n\",\n \" coverage_max: 0.85\\n\",\n \" coverage_std_min: 0.065\\n\",\n \" max_overlap: 0.8\\n\",\n \" embed_model: text-embedding-3-small\\n\",\n \" embed_backend: auto\\n\",\n \"\\n\",\n \"Role Assignments: bird_column_level_rbac_assignments_v2_20251230.json\\n\",\n \"Dataset: column_level_rbac_dataset_bird_20251230.json\\n\",\n \"Schema Dir: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev_databases\\n\",\n \"\\n\",\n \"✓ Quality evaluator initialized with custom thresholds\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 5.1 Setup Quality Evaluator (force reload all modules)\\n\",\n \"import importlib\\n\",\n \"import sys\\n\",\n \"from pathlib import Path\\n\",\n \"import glob\\n\",\n \"\\n\",\n \"# Force reload the entire module tree\\n\",\n \"if 'src.role_evaluator.quality_metrics' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator.quality_metrics']\\n\",\n \"if 'src.role_evaluator.quality_visualizer' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator.quality_visualizer']\\n\",\n \"if 'src.role_evaluator' in sys.modules:\\n\",\n \" del sys.modules['src.role_evaluator']\\n\",\n \"\\n\",\n \"from src.role_evaluator import RoleQualityEvaluator, RoleQualityVisualizer, print_quality_report\\n\",\n \"\\n\",\n \"# Configure paths\\n\",\n \"project_root = Path.cwd().parent if Path.cwd().name == 'notebooks' else Path.cwd()\\n\",\n \"\\n\",\n \"# Find most recent dataset and role assignments files\\n\",\n \"role_files = sorted(glob.glob(str(project_root / 'outputs' / 'column_level_role_assignments_bird_*.json')))\\n\",\n \"ROLE_ASSIGNMENTS_PATH = role_files[-1] if role_files else str(project_root / 'outputs' / 'column_level_role_assignments_bird.json')\\n\",\n \"\\n\",\n \"# Check for v2 role assignments (after regeneration)\\n\",\n \"role_files_v2 = sorted([f for f in glob.glob(str(project_root / 'outputs' / 'bird_column_level_rbac_assignments_*.json'))\\n\",\n \" if 'v2' in f])\\n\",\n \"if role_files_v2:\\n\",\n \" ROLE_ASSIGNMENTS_PATH = role_files_v2[-1]\\n\",\n \"\\n\",\n \"dataset_files = sorted([f for f in glob.glob(str(project_root / 'outputs' / 'column_level_rbac_dataset_bird_*.json')) \\n\",\n \" if 'metadata' not in f])\\n\",\n \"if not dataset_files:\\n\",\n \" raise FileNotFoundError(\\\"No RBAC dataset found in outputs/\\\")\\n\",\n \"DATASET_PATH = dataset_files[-1]\\n\",\n \"\\n\",\n \"SCHEMA_DIR = str(project_root / 'data' / 'Bird' / 'dev_20251106' / 'dev_databases')\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# CONFIGURABLE QUALITY THRESHOLDS\\n\",\n \"# Adjust based on dataset characteristics\\n\",\n \"# BIRD has larger DBs with more columns, so thresholds differ from Spider\\n\",\n \"# ============================================================\\n\",\n \"QUALITY_THRESHOLDS = {\\n\",\n \" \\\"deny_rate_min\\\": 5.0, # Warn if deny rate < this (roles too permissive)\\n\",\n \" \\\"coverage_max\\\": 0.85, # Warn if avg coverage > this (roles too broad)\\n\",\n \" \\\"coverage_std_min\\\": 0.065, # Warn if coverage std < this (low diversity)\\n\",\n \" \\\"max_overlap\\\": 0.80, # Warn if max overlap > this (redundant roles)\\n\",\n \"}\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EMBEDDING MODEL CONFIGURATION\\n\",\n \"# Backend auto-detected based on model name, or set explicitly\\n\",\n \"# ============================================================\\n\",\n \"# OpenAI models (requires OPENAI_API_KEY):\\n\",\n \"# - \\\"text-embedding-3-small\\\" (default, cost-effective)\\n\",\n \"# - \\\"text-embedding-3-large\\\" (higher accuracy)\\n\",\n \"# - \\\"text-embedding-ada-002\\\" (legacy)\\n\",\n \"# \\n\",\n \"# BAAI/fastembed models (local, no API key needed):\\n\",\n \"# - \\\"BAAI/bge-small-en-v1.5\\\" (fast, lightweight)\\n\",\n \"# - \\\"BAAI/bge-base-en-v1.5\\\" (balanced)\\n\",\n \"# - \\\"BAAI/bge-large-en-v1.5\\\" (best accuracy)\\n\",\n \"# ============================================================\\n\",\n \"# EMBED_MODEL = \\\"BAAI/bge-small-en-v1.5\\\"\\n\",\n \"EMBED_MODEL = \\\"text-embedding-3-small\\\"\\n\",\n \"EMBED_BACKEND = None # None = auto-detect, or \\\"openai\\\" / \\\"fastembed\\\"\\n\",\n \"\\n\",\n \"print(\\\"=== Quality Thresholds (Configurable for BIRD) ===\\\")\\n\",\n \"for k, v in QUALITY_THRESHOLDS.items():\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"print(f\\\" embed_model: {EMBED_MODEL}\\\")\\n\",\n \"print(f\\\" embed_backend: {EMBED_BACKEND or 'auto'}\\\")\\n\",\n \"\\n\",\n \"print(f\\\"\\\\nRole Assignments: {Path(ROLE_ASSIGNMENTS_PATH).name if ROLE_ASSIGNMENTS_PATH else 'Not found'}\\\")\\n\",\n \"print(f\\\"Dataset: {Path(DATASET_PATH).name if DATASET_PATH else 'Not found'}\\\")\\n\",\n \"print(f\\\"Schema Dir: {SCHEMA_DIR}\\\")\\n\",\n \"\\n\",\n \"if ROLE_ASSIGNMENTS_PATH and DATASET_PATH:\\n\",\n \" evaluator = RoleQualityEvaluator(\\n\",\n \" role_assignments_path=ROLE_ASSIGNMENTS_PATH,\\n\",\n \" dataset_path=DATASET_PATH,\\n\",\n \" schema_dir=SCHEMA_DIR,\\n\",\n \" embed_model=EMBED_MODEL,\\n\",\n \" embed_backend=EMBED_BACKEND,\\n\",\n \" thresholds=QUALITY_THRESHOLDS\\n\",\n \" )\\n\",\n \" print(\\\"\\\\n✓ Quality evaluator initialized with custom thresholds\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"\\\\n Missing files - generate roles and dataset first\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 74,\n \"id\": \"8135e2e3\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[embedding_utils] Using OpenAI embeddings (text-embedding-3-small) for 11 texts\\n\",\n \"[embedding_utils] Using OpenAI embeddings (text-embedding-3-small) for 47 texts\\n\",\n \"Overall: 11 databases, 53 roles, 7252 entries\\n\",\n \"Pass Rate: 100.0% (11/11 pass)\\n\",\n \"\\n\",\n \"Using Thresholds: deny_rate_min=5.0%, max_overlap=80%, coverage_std_min=0.065\\n\",\n \"\\n\",\n \"=== Deny Rate Analysis ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseDeny%AllAllow%AllDenyRolesStatus
0california_schools73.5%1.1%05OK
1card_games46.9%2.1%05OK
2codebase_community37.8%0.0%05OK
3debit_card_specializing54.7%0.0%06OK
4european_football_257.1%1.6%05OK
5financial70.6%0.0%05OK
6formula_144.7%8.7%04OK
7student_club49.9%1.3%05OK
8superhero49.1%0.0%05OK
9thrombosis_prediction33.7%2.5%04OK
10toxicology47.4%11.7%04OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Deny% AllAllow% AllDeny Roles Status\\n\",\n \"0 california_schools 73.5% 1.1% 0 5 OK\\n\",\n \"1 card_games 46.9% 2.1% 0 5 OK\\n\",\n \"2 codebase_community 37.8% 0.0% 0 5 OK\\n\",\n \"3 debit_card_specializing 54.7% 0.0% 0 6 OK\\n\",\n \"4 european_football_2 57.1% 1.6% 0 5 OK\\n\",\n \"5 financial 70.6% 0.0% 0 5 OK\\n\",\n \"6 formula_1 44.7% 8.7% 0 4 OK\\n\",\n \"7 student_club 49.9% 1.3% 0 5 OK\\n\",\n \"8 superhero 49.1% 0.0% 0 5 OK\\n\",\n \"9 thrombosis_prediction 33.7% 2.5% 0 4 OK\\n\",\n \"10 toxicology 47.4% 11.7% 0 4 OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Semantic Quality (Similarity: role-schema alignment, Coverage: column access, Diversity: coverage std) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseSimilarityCoverageDiversityStatus
0california_schools0.690234.8%0.0996OK
1card_games0.684350.0%0.2965OK
2codebase_community0.633260.6%0.2888OK
3debit_card_specializing0.626463.8%0.1299OK
4european_football_20.679931.3%0.0984OK
5financial0.641046.8%0.1288OK
6formula_10.659944.0%0.1480OK
7student_club0.678050.5%0.1701OK
8superhero0.683561.3%0.1895OK
9thrombosis_prediction0.660769.3%0.3798OK
10toxicology0.669869.7%0.1134OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Similarity Coverage Diversity Status\\n\",\n \"0 california_schools 0.6902 34.8% 0.0996 OK\\n\",\n \"1 card_games 0.6843 50.0% 0.2965 OK\\n\",\n \"2 codebase_community 0.6332 60.6% 0.2888 OK\\n\",\n \"3 debit_card_specializing 0.6264 63.8% 0.1299 OK\\n\",\n \"4 european_football_2 0.6799 31.3% 0.0984 OK\\n\",\n \"5 financial 0.6410 46.8% 0.1288 OK\\n\",\n \"6 formula_1 0.6599 44.0% 0.1480 OK\\n\",\n \"7 student_club 0.6780 50.5% 0.1701 OK\\n\",\n \"8 superhero 0.6835 61.3% 0.1895 OK\\n\",\n \"9 thrombosis_prediction 0.6607 69.3% 0.3798 OK\\n\",\n \"10 toxicology 0.6698 69.7% 0.1134 OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Policy Overlap Analysis ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseAvgOverlapMaxOverlapStatus
0california_schools30.7%57.1%OK
1card_games11.9%23.8%OK
2codebase_community28.0%57.8%OK
3debit_card_specializing47.0%65.0%OK
4european_football_214.4%23.8%OK
5financial21.5%37.0%OK
6formula_129.3%32.9%OK
7student_club30.2%45.0%OK
8superhero33.0%52.6%OK
9thrombosis_prediction18.1%38.5%OK
10toxicology53.7%66.7%OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database AvgOverlap MaxOverlap Status\\n\",\n \"0 california_schools 30.7% 57.1% OK\\n\",\n \"1 card_games 11.9% 23.8% OK\\n\",\n \"2 codebase_community 28.0% 57.8% OK\\n\",\n \"3 debit_card_specializing 47.0% 65.0% OK\\n\",\n \"4 european_football_2 14.4% 23.8% OK\\n\",\n \"5 financial 21.5% 37.0% OK\\n\",\n \"6 formula_1 29.3% 32.9% OK\\n\",\n \"7 student_club 30.2% 45.0% OK\\n\",\n \"8 superhero 33.0% 52.6% OK\\n\",\n \"9 thrombosis_prediction 18.1% 38.5% OK\\n\",\n \"10 toxicology 53.7% 66.7% OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n }\n ],\n \"source\": [\n \"# 5.2 Run Quality Evaluations and Display as DataFrame\\n\",\n \"import pandas as pd\\n\",\n \"import importlib\\n\",\n \"\\n\",\n \"# Force reload modules to use latest code\\n\",\n \"import src.role_evaluator.quality_metrics\\n\",\n \"import src.role_evaluator.quality_visualizer\\n\",\n \"importlib.reload(src.role_evaluator.quality_metrics)\\n\",\n \"importlib.reload(src.role_evaluator.quality_visualizer)\\n\",\n \"\\n\",\n \"from src.role_evaluator.quality_metrics import print_quality_report\\n\",\n \"\\n\",\n \"# Set display options for full content (no truncation)\\n\",\n \"pd.set_option('display.max_colwidth', None)\\n\",\n \"pd.set_option('display.max_rows', None)\\n\",\n \"pd.set_option('display.width', None)\\n\",\n \"\\n\",\n \"if 'evaluator' in dir():\\n\",\n \" report = evaluator.evaluate_all()\\n\",\n \" \\n\",\n \" # Summary\\n\",\n \" print(f\\\"Overall: {report.total_databases} databases, {report.total_roles} roles, {report.total_entries} entries\\\")\\n\",\n \" print(f\\\"Pass Rate: {report.pass_rate:.1%} ({report.total_databases - len(report.databases_with_issues)}/{report.total_databases} pass)\\\")\\n\",\n \" print(f\\\"\\\\nUsing Thresholds: deny_rate_min={QUALITY_THRESHOLDS['deny_rate_min']}%, \\\"\\n\",\n \" f\\\"max_overlap={QUALITY_THRESHOLDS['max_overlap']:.0%}, \\\"\\n\",\n \" f\\\"coverage_std_min={QUALITY_THRESHOLDS['coverage_std_min']}\\\\n\\\")\\n\",\n \" \\n\",\n \" # Deny Rate DataFrame - Full display\\n\",\n \" if report.deny_rate_metrics:\\n\",\n \" deny_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"Deny%\\\": f\\\"{m.deny_rate:.1f}%\\\",\\n\",\n \" \\\"AllAllow%\\\": f\\\"{m.all_allow_pct:.1f}%\\\",\\n\",\n \" \\\"AllDeny\\\": m.all_deny_queries,\\n\",\n \" \\\"Roles\\\": len(m.roles),\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.deny_rate_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"=== Deny Rate Analysis ===\\\")\\n\",\n \" display(deny_df)\\n\",\n \"\\n\",\n \" # Semantic Quality DataFrame \\n\",\n \" if report.semantic_metrics:\\n\",\n \" sem_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"Similarity\\\": f\\\"{m.avg_similarity:.4f}\\\",\\n\",\n \" \\\"Coverage\\\": f\\\"{m.avg_coverage:.1%}\\\",\\n\",\n \" \\\"Diversity\\\": f\\\"{m.coverage_std:.4f}\\\",\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.semantic_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Semantic Quality (Similarity: role-schema alignment, Coverage: column access, Diversity: coverage std) ===\\\")\\n\",\n \" display(sem_df)\\n\",\n \"\\n\",\n \" # Policy Overlap DataFrame\\n\",\n \" if report.overlap_metrics:\\n\",\n \" ovl_df = pd.DataFrame([\\n\",\n \" {\\n\",\n \" \\\"Database\\\": db_id,\\n\",\n \" \\\"AvgOverlap\\\": f\\\"{m.avg_overlap:.1%}\\\",\\n\",\n \" \\\"MaxOverlap\\\": f\\\"{m.max_overlap:.1%}\\\",\\n\",\n \" \\\"Status\\\": \\\"WARN\\\" if m.issues else \\\"OK\\\"\\n\",\n \" }\\n\",\n \" for db_id, m in sorted(report.overlap_metrics.items())\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Policy Overlap Analysis ===\\\")\\n\",\n \" display(ovl_df)\\n\",\n \"else:\\n\",\n \" print(\\\" Evaluator not initialized\\\")\\n\",\n \"\\n\",\n \"pd.reset_option('display.max_colwidth')\\n\",\n \"pd.reset_option('display.max_rows')\\n\",\n \"pd.reset_option('display.width')\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 75,\n \"id\": \"89f843e7\",\n \"metadata\": {},\n \"outputs\": [],\n \"source\": [\n \"# # 5.3 Quality Dashboard Visualization\\n\",\n \"# import matplotlib.pyplot as plt\\n\",\n \"# from src.role_evaluator.quality_visualizer import RoleQualityVisualizer\\n\",\n \"\\n\",\n \"# visualizer = RoleQualityVisualizer(evaluator=evaluator, report=report)\\n\",\n \"# fig = visualizer.plot_quality_dashboard()\\n\",\n \"# plt.show()\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 76,\n \"id\": \"86eb26de\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Total roles: 53, SystemManager: 11\\n\"\n ]\n },\n {\n \"name\": \"stderr\",\n \"output_type\": \"stream\",\n \"text\": [\n \"/tmp/ipykernel_1782890/140258372.py:110: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.\\n\",\n \" plt.tight_layout(rect=[0,0,0.95,0.95])\\n\"\n ]\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Saved: /home/feiy/Role-SQL-benchmark/plot/column_level_rbac_semantic.png\\n\"\n ]\n },\n {\n \"data\": {\n \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAABtcAAAOzCAYAAADDRVknAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAXEgAAFxIBZ5/SUgABAABJREFUeJzs3XdYU9f/B/B3QtgblK1MweLAWdyg4t6tde9arbXVWq211jrraB1122pb96rWva3iFve2OBG3IsqQTXJ/f/AjX+O9gQCBgL5fz5NHc3LuuSfr5HI/93yOTBAEAURERERERERERERERESUK7mhO0BERERERERERERERERUUjC4RkRERERERERERERERKQjBteIiIiIiIiIiIiIiIiIdMTgGhEREREREREREREREZGOGFwjIiIiIiIiIiIiIiIi0hGDa0REREREREREREREREQ6Uhi6A0RERERERERERERUMgmCAEEQDN0NIqJ8k8lkkMlkedqGwTUiIiIiIiIiIiIi0plSqURsbCwSExORnp5u6O4QERWYiYkJrK2t4ejoCCMjo1zrywReVkBEREREREREREREOlAqlbh//z5SU1MN3RUiIr0zMzND2bJlcw2wceYaEREREREREREREekkNjYWqampMDIygrOzMywtLSGXyw3dLSKifFOpVEhKSsKzZ8+QmpqK2NhYODk55bgNg2tEREREREREREREpJPExEQAgLOzM2xtbQ3cGyKigpPL5erx7PHjx0hMTGRwjYiIiIiIiIiIiIgKThAE9RprlpaWhbafzLQ0XFi6BKpMJar3HwiFmVmh7YuIKFv2uJaeng5BECCTybTWZXCNiIiIiIiIiIiIiHIlCIL6/4WZCvL6xvU4MnkiAMDY3BzVPh1QaPsiIsr25riWW3CNyXCJiIiIiIiIiIiIqFhQZWbi9MJ56vsR82YjPem1AXtERCTG4BoRERERERERERERFQs3tm9B/P1omEAGC5kcKbEvcOGvPwzdLSIiDQyuEREREREREREREZHBCSoVTs2fAwDwMjZDORMLAMCZ3xYgNT7ekF0jItLA4BoRERERERERERERGdztvbsRe/MGFJDB09gMbkYmsJIZIS0hHmd/X2jo7hERqTG4RkREREREREREREQGJQgCTs2bDQDwNDaDsUwOmUwGfxNzAMD5P39H8osYA/YQSEhIwJgxY1ChQgWYm5vDwsIC3t7eaNWqFaZPn4709PRC2/eyZcsgk8mwbNmyQttHfshkMshkMri6ukKpVErWWbBggbre+PHji7aDRIWEwTUiIiIiIiIiIiIiMqjow+F4duUSjAB4G5upy52NTGArN0JGcjJOL5hrsP7FxcUhODgYkydPhkwmQ9++fTFs2DDUr18fV69exciRI5GQkGCw/hmSQqHA06dPsW/fPsnHly9fDoVCUcS9Iipc/EQTERERERERERERkUFF/P+stTIKM5jI/jcnRCaTwd/YAmfSEnFxxTJUHzAI1q5uRd6/2bNnIzIyEl988QUWLFggevzIkSOwtLQs8n4VB0FBQXjw4AFWrFiBFi1aaDwWGRmJM2fOoFWrVti5c6eBekikf5y5RkREREREREREREQG8/BUBB6djoAcgM8bs9aylTIyhoNcAWV6GiLmzir6DgI4ffo0AGDAgAGSjzdo0ADm5uZYvXo1ZDIZ5s+fL1lvxIgRkMlkOHz4sLps9erVqFWrFhwcHGBhYQFPT0907twZ//33HwCgT58+6Nu3LwCgb9++6hSLoaGhGm2fPHkSbdu2haOjI8zMzFCxYkXMmTMHgiBo1Bs/fjxkMhkOHTqE33//HeXLl4e5uTkqVaqE7du3AwBevXqF/v37w9nZGRYWFmjdujUePnwo+ZwUCgW6deuGLVu2iGbvLV++HMbGxujatavktrt27UK3bt3g6+sLMzMz2Nvbo0WLFjhx4oSo7pupMbds2YJq1arBzMwMZcuWxdSpU0X17927h1GjRqFatWqwt7dXP8dZs2ZBpVKJ6guCgFmzZqFcuXIwMzNDQEAA5s+fj0OHDmlNyblr1y40btwYdnZ2MDc3R40aNbB69WpRvT59+kAmk+H27duYNGkSfH19oVAoil2aT9Idg2tEREREREREREREZDCn5v0KAHBXmMJMbiR6PGvtNQsAwNV1axAXfa8ouwcAcHBwAADcunUrx3off/wx7OzsJIMmmZmZWLVqFXx9fdGgQQMAwNy5c9GjRw+8fPkSPXr0wFdffYW6devi0KFDuHTpEgCgffv2aNeuHQCgXbt2GDduHMaNG4c+ffqo216/fj3q16+vDrB98cUXUCgU+Prrr/HFF19I9nXmzJkYM2YM6tevj169euHu3bv46KOPEBERgYYNG+LixYvo3r076tevj507d6JLly5an3evXr2QmpqKv//+W12mUqmwatUqtGzZEo6OjpLbTZw4EZcuXUK9evXw9ddfo3379oiIiEBoaCiOHTsmuc3mzZvRrVs3lC9fHoMGDYKJiQlGjx6NuXM104bu2bMHv/32G7y9vdGvXz989tlnUCgUGD58OAYPHixq97vvvsPw4cOhVCrx5ZdfolGjRvjxxx8xffp0yX7MmDEDrVq1wu3bt9GpUyd89tlniI+PR48ePfDzzz9LbjN48GAsXLgQDRs2xFdffQVnZ2fJelQCCEREREREREREREREuVAqlcL169eF69evC0qlUi9tPrl4QZjhUVqY6VFaOFuunHA9oLzW23JPN2GGR2lh19Av9LLvvNi0aZMAQLCyshJGjBgh/Pvvv0JiYqJk3S+++EIAIFy5ckWjfNu2bQIAYdKkSeqyqlWrCu7u7kJycrJG3YyMDCEuLk59f+nSpQIAYenSpaL9PX36VLC0tBQqVqwoxMbGqsszMzOFjh07CgCEkydPqsvHjRsnABCcnJyEBw8eqMs3b94sABBsbW2FHj16aLzH7dq1EwAIp0+f1tg3ACE4OFgQBEGoWLGiUK9ePfVj+/fvFwAI//zzj7B7924BgDBu3DiN7e/evSt6Ps+ePRM8PDyE0NBQjfLs18DExEQ4d+6cuvzVq1eCo6Oj4Ovrq1H/yZMnQkpKiqj9AQMGCDKZTIiKilKXXbt2TZDL5UJgYKDw+vVrdfmtW7cECwsL0Wt/6dIlQS6XC2FhYUJSUpK6PDk5WahTp46gUCg0XtvevXsLAAQfHx/h6dOnoj5R8ZCXMY4z14iIiIiIiIiIiIjIIE7Nnw0AcDUygYXErLU3+RtnzV67vmkjXtyILOyuaejQoQMmT54MpVKJGTNmICwsDLa2tqhatSqmTJmCxMREdd1PP/0UAESz15YtWwa5XI7evXtrlJuYmMDISPO5KxQK2Nra6tS3lStXIikpCdOnT1fPsAMAIyMjjB8/HgCwYcMG0XZDhgyBh4eH+n7btm1hYmKC+Ph4TJs2DXL5/8IHn3zyCQDg6tWrWvvRq1cvHD9+HFFRUQCAFStWwMHBAa1bt9a6jbe3t6jMyckJH330EY4fP4709HTR4z169EC1atXU9+3s7NC2bVvcuXNH431wcXGBmZk4zejnn38OQRBw6NAhddn69euhUqkwatQojbXz/Pz8RO8XACxevBgqlQrz5s2DhYWFutzc3ByjR49GZmYmNm/eLNpuxIgRnK32jmBwjYiIiArNvXv31Lng37wRFTf8rL4/Fi9erPEee3t7IyMjw9Ddeqf88ccfGq+xr68vUlNTDd2tYk9qDLp3756hu1VihIaGil4/rmHybtL1vc5e2+bNW/YJZiIqPmJv3sDtPbsAAL4m5rnWtzVSwNnIBBAEnJgpnXavMI0ePRqPHj3CypUrMWjQIAQFBeHSpUv44YcfUL16dcTHxwMAqlWrhipVqmDVqlXIzMwEAMTGxmLHjh1o3LgxypQpo27zk08+QVRUFCpXrowJEybg6NGjkgGlnGSvB3fgwAGMHz9e47ZmzRoAwI0bN0TbVa5cWeO+XC6Hk5MTHBwc4O7urvGYi4sLAODx48da+9G9e3fI5XKsWLECr1+/xqZNm9C5c2eYmJho3SYuLg6jRo1CYGAgzM3N1WP23LlzkZGRgdjYWNE2QUFBojI3Nzd1e29as2YNQkNDYW9vD7lcDplMpg7MPXnyRF3v8uXLAIDatWuL2pYqO336NBQKBdatWyd6zXftyvpMS73mbwYFqWRTGLoDREREpD8pKSnYunUrjhw5gtOnT+Pp06d4+fIllEolbG1t4e3tjcqVK6Nx48Zo2bIlbGxsDN1lKiRSgaFx48bxpFIRCg0N1VikXIqFhQVsbGzg6+uL6tWr4+OPP1avvaDNsmXL1IuZa2NqagoLCwu4uroiICAADRs2RKdOnfJ8hWRMTAzc3d0lg0/ly5dXL7CeH3fv3sW2bdtw7NgxXL16FbGxsYiLi4OpqSkcHR0REBCADz/8EM2bN0fdunX1Eux88eIFvv/+e42y0aNHw9jYWFTXy8sL0dHRWtuSy+WwsLBQj63VqlVDmzZtEBYWlmMfpD4XISEhGlfN6toHmUwGCwsL2NnZoVy5cggODkanTp1y/YN9/PjxmDBhgmR7xsbGMDExga2tLRwdHeHp6YnAwECEhoaiadOmGlcva9O7d2/89NNP6r7fvXsXU6dOldxnYTt06BAaNmyYYx2FQgErKys4Ozvjgw8+QJMmTdC5c2et64JQlvT0dGzbtg2bN2/G+fPn8fTpUyQmJsLY2BjW1tZwc3ODj48PgoKC1DepK9Pp/ZGRkQF3d3fExMSIHrOzs8OTJ08kZxcQ0bvt1II5AABnIxNYy3U7Ve1vYo5nKem4tXsnnl2+BOfK4kBLYbK3t0ePHj3Qo0cPAEB0dDT69OmDQ4cOYeLEiZg5cyaArNlrX331FXbv3o02bdpg9erVSE9PR79+/TTaGzVqFGxtbbFo0SJ1cMbGxgb9+/fHlClTYGpqmmufXr16BSBrDTBtkpKSRGXW1taiMiMjI63lAHK8MM3NzQ2NGzfGihUr4OXlhaSkJPTq1Utr/bS0NDRo0ABXr15FvXr10KRJE9ja2kIul+PQoUM4fPgw0tLSRNtJnctQKLI+P0qlUl02ZcoU/PDDD/D09ESHDh3g4uICExMTxMXFYc6cORptZ894K126tKhtJycnUdmrV6+QmZmZ4zGu1Gsu1RaVTJy5RkRE9A5IT0/HpEmTULZsWXTt2hWLFi3CuXPn8OjRI6SkpCA9PR0xMTE4ffo0/vjjD3Tt2hVubm74888/Dd11ovdacnIynj59iuPHj2Pu3LkICQlBWFgYXrx4UaB209LS8OrVK1y/fh2bN2/GkCFD4O3trf5DX1erV6/W+sdzZGQkIiIi8ty3mzdvomPHjihXrhyGDRuGf/75Bzdu3MCLFy+QmZmJpKQk3L9/H/v378fkyZNRv359BAQE4MGDB3ne19smTZqEly9fqu+XLVtWYxH4vFCpVHj9+jUePXqEY8eOYe7cuWjSpAk+/PDDHANi+iQIApKSkvDo0SMcOnQIP//8M6pXr46uXbsiOTk5X+2lp6ern9fly5exfft2/Pzzz2jRogV8fHwwY8YM9dXX2hgbG2P06NEaZTNmzNC4Mrg4yczMRFxcHG7cuIEtW7Zg8ODB8PHx4aynHJw9exZBQUH45JNPsGbNGkRGRiIuLg5KpRKpqamIiYnBpUuXsHnzZowfPx4dOnTABx98YOhuk4Ht3LlTMrAGZM0y2LJlS9F2iN4ZnLlacsVF30Pk1qy0eX7Guc9ay2YtV8DNKGsm1LHpUwulb3nh6emJv/76CwBw7NgxdXn37t1hZmam/jwuW7YMdnZ2aN++vcb2MpkMX3zxBa5cuYJHjx5hxYoVCAwMxKxZs/Djjz/q1IfsYNjDhw8hCILkLTw8vOBPVge9evXC3bt3MXr0aPj7+6NWrVpa627duhVXrlzBTz/9hCNHjmDOnDmYOHEixo8fX+Bjh8zMTEybNg1BQUH477//8Ndff2HKlCkYP348unbtKqqf/RpK/VY9f/5csr6pqSmUSqXW13zp0qWi7Zgh5d3B4BoREVEJd/v2bdSqVQtjx47N0wn5pKQkXLlypRB7RkT5ceDAATRv3lzjikt9SElJwYgRI7BkyRKdt8ntxFReT1ytWLEC1apVwz///AOVSqXzdrdu3ZJMB5MXDx8+xG+//aZRNnToUMlZawVx5swZNG7cGCkpKXptNy/WrVuH7t27673d6OhofPvttwgJCck12NmnTx+UKlVKfT85ORlTpkzRe58KS0JCAvr27cuT/RIuX76Mxo0bIzKyaNe5oZJP378puQkLC8PgwYM1bh9++KFe90FEBXNm0TwISiVKGxnD1ihvCdbKmVhABuDeoYN4eDrvF3zpm5WVFQDNmUr29vbo0KEDduzYgYMHD+LChQvo2rVrjrN03dzc0LNnTxw8eBBWVlbYvn27+rHsDAJSx9E1a9YEAJw6dUovz6cgOnToAGtrazx+/Bg9e/bMse7du3cBZK319iZBEHDy5MkC9ePFixdITExEWFgYzM01g7fHjx8X1c9OkSl1AaFUWc2aNZGWloaLFy8WqJ9UcjEtJBERUQn26NEjNGzYEA8fPpR8PCAgAFWqVIGtrS3i4+Nx8+ZNXL58We8n7YlIN25ubujQoQOArLQj//33H86cOSOqd+7cOWzcuBGdO3fWue1evXqpr7ZMTEzEsWPH1H+svmnChAno379/rldMXrx4EZcuXcqxzvr16zF79myd0ngtX75c6ywxExMT1K5dG15eXlAoFIiJiVHPvtWXX3/9VWPtCiMjI3Tr1i1PbZQvXx6NGzcGkHVSIzo6Gnv37hWNqXfu3MHKlSsxYMCAgnc8hz68evUKly5dwrVr10T1tmzZglOnTiE4OFjntgcPHgwgKxD2/PlznD59WvLK3RMnTqBu3bo4ffq0eu2Nt5mYmKBz585YsGCBuuyvv/7CuHHjNIJuhtK+fXu4u7tDqVTiyZMnOHLkiDqd0pu+//570dXl77svv/wSCQkJGmVyuRzBwcHw9/eHubk5EhISEBUVhStXruD169cG6ikVJzExMer1Z7TZv38/Hj16JFrjJ7/eTNlGRMVP4pMnuLZhPQDANw+z1rJZyo3goTDFg8w0HP9lKjpt2FLoM4IWL16MDz/8EFWqVBE99ssvvwAA6tatq1H+6aefYu3aterxSCq9+5EjR0Sp4ePj45Genq6REtLBwQEAJI+Re/fujUmTJmHkyJGoUaMGypYtq/F4dHQ0BEGAl5dX7k+0gCwsLLB7927ExMSgfv36OdbNXnvu+PHjqFixorp89uzZuf4tkpvSpUvDzMwMJ0+ehCAI6s/HzZs3MXWqeMZj586dMWnSJPz888/46KOPYGFhASDr2H758uWi+gMHDsQff/yBwYMHY8eOHaKU4v/99x8cHR2ZBvIdxuAaERFRCaVSqdCuXTvJwNqHH36IBQsWoEaNGqLHXr16heXLl2PWrFlF0U0iekO5cuUwf/58jbKlS5eK1l0AgH379uUpuDZhwgSNP5YzMjLQunVr7Nu3T6Peo0ePcPv2bZQrVy7H9nSZQZCdxqtLly451jt79iw+++wzUblMJsPXX3+NH3/8Efb29qLHL126hIULF6rT7ORXamqqqI0mTZpoDQxpExwcLHr/wsPDERYWJrqC+PDhw4USXJPqw7hx4zBx4kRR3X379uUpuPZ2uwCwe/dujBw5ElevXtUof/DgAdq3b48TJ05oXYetR48eGsG15ORkLFu2DCNGjNC5T4Vl6NChCA0NVd+Pj49H/fr1RTO6IyMj8eDBA/WJn/dddHQ0jh49qlFmbW2Nf//9V3JGkFKpxIkTJ7BlyxZs2LChqLpJxVBOaYazqVQqrFy5EqNGjSqiXhGRIZ39fSGU6elwkCvgYJS/TAJ+xuZ4lJmGh6dOIvrIIXiF5LzOakHt2rULAwcOxAcffIA6derA2dkZr169wuHDh3H9+nWUKVNGlMaxUaNG8PLywr1791ChQgX1DLM3tW3bFo6Ojvjwww/h6emJ+Ph4bNmyBenp6Rg2bJi6Xq1atWBqaopff/0Vr169goODAzw9PdGzZ0+4ublh6dKl6NmzJz744AO0atUK3t7eePnyJSIjI3HixAmsXr26SIJrgDjIqE2bNm3g7u6OL7/8EocOHYK7uzvOnj2LkydPomXLlrlemJETIyMj9O/fH/Pnz0fNmjXRsGFDPH78GNu2bUOTJk2wefNmjfqBgYEYNmwYZs2ahUqVKuGjjz5CUlIS1q1bh5CQEOzatUvjuLdatWr45Zdf8O2338Lf3x/NmzdHmTJl8OzZM1y9elX9PBhce3cxLSQREVEJtXLlSpw7d05U3qhRIxw+fFgysAZkpab4+uuvERkZKZlnPFt6ejpWrVqF7t27w9/fH3Z2djA2NkapUqUQFBSEzz//HP/++69ensuhQ4dE6yRoO+hftmyZqO6bJ0h1qXfjxg0MGDAAXl5eMDMzQ9myZdG9e3dROof79+/jm2++UV+J7+joiLCwMKxfvz7H5/P2fmUyGe7duwdBELB27Vq0aNECLi4uMDU1hZubGz755JN8rV1V1O7du4dx48ahUaNGcHd3h7m5OSwtLeHt7Y1OnTph9erVWtdiatSokeg1yelE68OHD2FkZKRR38bGRnJBaCBrJs3QoUNRs2ZNODk5wcTEBHZ2dggMDMTAgQNx+PBhvbwGhaFv377w8PAQlT9+/LhA7RobG6N///6Sj+WWYjEjIwNr1qwRlUulddElCDdy5EjJk6q//fYbZs2aJRlYA4CgoCD8/vvvuHz5MlxdXXPdjzbbtm1DXFycRtknn3yS7/be1LBhQ5QvX15UXtA0lnkxevRo9QLzbyroZwgAWrRogYiICNHV1EBW2qG1a9dq3bZWrVqioNSKFSu01td1fC8Mtra2GDJkiORjub2OKpUKW7duRb9+/VChQgU4OjrC2NgYDg4OCAwMRN++fbF58+Y8pULVVVGPfZcvXxaVNWzYUGuqPSMjI9SvXx8zZ87EnTt3dNrHiRMn8PXXX6N27dpwdXWFmZkZbGxsUK5cOYSFheGnn36SPP7Jyfnz5/Hpp5+qf/cdHR3RqFEjrFmzBoIg5Lq9IAjYu3cvBg4ciKCgIJQqVQomJiZwdHRElSpVMHTo0FxTQhnyuOTixYv4/fffMXDgQNStWxcBAQHqz4ulpSXc3NwQGhqKkSNHFniWgDZSV/xL/aZI1cuvPn36iF7z8ePHa63/+vVrTJ48GVWrVoW1tTVsbGxQqVIlfP/99+q1dnRd2yunfV+7dg2ff/45fH19YW5uDjs7O9SpUwcLFy7McU1LbceXqampmDFjBqpXrw5ra2s4ODigXr16WLZsmcbnOzMzE4sXL0adOnVgb28PS0tLVKxYET/88IPkzF0pBTkWzObl5SV6HocOHQKQdUHHxx9/DHd3d5iamsLJyQmtWrXCnj17RO28+feD1FjXt29f0X7yu84q6V9y7AtcXp31fc/PrLVs5nIjlFVkZVA49stUncb0gvj5558xdepUuLi4YP/+/ZgxYwZWrFgBhUKBUaNG4cKFC6LjeplMps6WIHVBHQBMnToV5cuXx7Fjx/Drr79i69atCAoKwr59+9C7d291vVKlSmHt2rUoW7YsFi5ciB9//FFjHfXOnTsjIiICbdq0wdGjR/Hrr79ix44dEAQB06ZNQ1hYWCG8KgVjY2ODAwcOoFmzZti3bx8WL14MhUKBw4cPSwYi82rGjBn44Ycf8PLlS8ybNw/nzp3DhAkTtK5FPWPGDEyfPh0AMHfuXBw4cAATJ05Uv3fZmUKyDR8+HAcOHECdOnWwb98+zJo1C//++y9sbW2xYMECVKpUqcDPgYoxgYiIiEqkypUrCwA0bhYWFsKTJ08K3PaePXsEd3d3UftSt5o1awo3btyQbCcqKkpym7eFh4eL6nh6ekq2uXTpUlHdkJAQneutWLFCMDMzk+yXiYmJsHr1akEQBGH79u2Cra2t1uf96aefan39pOqfPXtWaNCggdb25HK58Mcff+T+5uhIah/jxo3LV1vJycnCoEGDBCMjo1w/D+XKlRPOnTsnamP16tWium3bttW6z19++UVUf8CAAaJ60dHRQsOGDXX6rDZr1kx4/vy55P50/azmRUhIiE6fVUEQhA8//FBUt3Xr1pJ1pT7bAISoqChR3b///lvnum/asmWLaBsvLy/h2bNnos+BXC4XHj58qLWt8+fPS/ahQ4cOOfZBn7p27Sraf2RkZI7beHp6irbp3bu3ZN3AwECd6+blc5GXPjg5OYnqfvnll5J1x40bl+fP++PHjwULCwvRNkFBQTlu17lzZ9E2d+7ckayr6/ieF1K/LwCE8PBwUd1du3ZpHb+1OXPmjFC+fHmdxiB/f3/h1KlTWtvKy3dVX2NfXkmN5eXKlROSk5ML3HZkZKRQu3ZtnZ6T1OdO6ru1dOlS4ccff8zx90vbdyrb5cuXhSpVqujUr549ewqvX7+WbMeQxyW+vr469T/71qdPHyElJUXn9y43ly5dEu3DwsJCePXqleDg4CB67OTJkzm2p+29flvv3r1F9bQdC127dk0oU6aM1tfEwcFB2L9/f4H3PWXKFEGhUGjdT5MmTYS0tDTJPkrVP3LkSI5jUPv27YX09HTh6dOnQp06dbTW8/b2FqKjo7W+5vo4Fswm9du2a9cuoWPHjjm2+/Z7p218z+mW2/eddKNUKoXr168L169fF5RKZb7aODptsjDDo7SwuKyLcM0/QLgeUD7ftwv+/sKvHk7CDI/Sws3dO/X8bPWjbdu2gkKhEJ49e2borlA+jR07VgAgXL161dBdoUKWlzGOM9eIiIhKoIcPH0pePd6tW7c8pzl727Jly9CiRQud1zo6c+YMatSoUSIW8b1y5Qr69u2L1NRUycfT09Px6aefYsWKFejYsSPi4+O1tvXnn39i1apVOu+7devWOHLkiNbHVSoVBg8ejFu3buncZlFISkpCaGgoFi1apNNafbdu3ULdunVx7NgxjfKPPvpINDtp9+7dePnypWQ7Uq/t22kFIyMjUa1aNYSHh+faLwDYu3cvgoODJdeQMrQHDx6Iyt5ccyA/MjMzJdMpVqpUKdd0MFJX4Xfp0gVOTk5o2FAz3U52Gi9ttKVyGT58eI590Ke3PyMODg7w9/fXS9tHjhxBZGSkqLxNmzZ6aV8XKSkpePHihai8oJ+hN7m6ukquXXTp0qUcfy9q164tKjt48KDe+qVPUt9DhUKBgIAAyfr79+9H3bp1Jd9/KTdv3kS9evWwd+/eAvXTkGOfs7OzqOzWrVuoUqUKpk6diuPHj2udYZyTEydOoHr16jh58mSB+/imKVOmYNKkSTn+fi1fvlzrjMqjR48iODhY52OclStXomHDhkhJSdGpviGPS3KybNkyrbMr8mPp0qWisrZt28LOzg4fffSR5P6L0tOnT9GwYUPJMSDby5cv0a5duwIdp/3+++8YPXp0jjO79u/fj2nTpunc5scff5zjGLRlyxaMHz8e7dq1w4kTJ7TWi4qK0vqe6+tYMCf9+vXDxo0bc6wzYcKEYp2JgHSXGh+PC8uzZlv5GZsXeJ00U5kcXsZZs9dOzPgZqmK2vvjt27exc+dOtG3blukBS4Dnz5+Lsg3cvn0bc+fOhY+PDwIDAw3UMyqOuOYaERFRCaQthWDTpk0L1O6lS5fw2WefidJpmJqaokmTJnB1dUVkZKRovZXExES0bdsWN27cgLl5/tN6FLbsQE6ZMmUQFhaGhw8fYv/+/Rp1UlNT1ak3bGxs0KpVK2RkZGDbtm1IT0/XqPvrr79KnmyW8vTpUwBAgwYN4O/vjzNnzohSL6WlpWHRokXFaj28zz//HKdPnxaV16hRAxUqVEBKSgqOHj2KJ0+eqB9LTU3FRx99hBs3bqgDamZmZujZsyfmzp2rrpeRkYH169dj0KBBGm1fvXpVFDwOCgrSSHWalpaG1q1bi1LvKRQKNGzYEGXLlsXz58/x77//apzkjIqKQrdu3UTvuyH9/vvvGq8fkJVKTSpdVk7GjRunTlPy+vVrHD9+HLdv39aoY25ujoULF+bYzosXL7Bz505Refa6al26dBGlhF2+fLnWNXKkTpZbW1ujVq1aOfZDXx49eqT+/mWrWrVqvk7knDp1Cl9++SWArKDi/fv3sXfvXtEf4O3bt0eHDh3y3+k8EAQBP/30k6gPVlZW+Pjjj/W6r7CwMCxevFhUfvLkSXTs2FFym+rVq4vKzpw5ozVlqaG8evUKc+bMEZV37NgRVlZWovKnT5+iY8eOot8FIyMj9doq0dHROHDggMbJ6IyMDHzyySe4ceNGvlKdGnrsq1WrFqysrPD69WuN8ps3b2L06NEAALlcjoCAANSuXRuhoaFo27YtbG1ttbb54sULtGnTRjIo5+DggAYNGsDJyQnx8fE4d+6caFzLSXYgpHz58qhbty4ePnwoGdycPXs2evXqpVEWExODdu3aiQJl5ubmaNSoEVxcXPDw4UMcOHBAI1hy5swZDBkyBEuWLMm1f0V9XOLt7Q1PT084OjrCwcEBMpkMMTExOHfuHO7fv69Rd+3atRg6dGie1m2UkpmZKZlm+M3flD/++EPjsfXr12P27NkwMzMr0L51NXjwYHXaxzd5enqiUaNGSElJwd69e/Hq1SskJyfnez/Zv0VlypRB48aNERcXh+3bt4sCVvPnz8fo0aOhUOR+yi4mJgYmJiZo2bIlLCwssGfPHtGFS1OmTFH/PzQ0FF5eXjh06BDu3bunUe/AgQO4cuWKKIWZvo4Fc5L92lSvXh1Vq1bFf//9h+PHj4vqzZkzByEhIQAAd3d3DB48GACwefNmUQrfxo0bi9I2F9WxB+Xs4vK/kJ6YCCuZEZyNTPTSpo+xGaIzUvHixn+4sW0LPuig32Og/Ni5cyfOnj2rTkHM9SRLhsWLF+Ovv/5CaGgonJycEBUVhe3btyM9PR3Lly8vcDCY3jFFMZWOiIiI9Gv+/PmSqU4uXLhQoHZbt24tatPJyUmUPm3Tpk2CTCYT1Z0xY4ZGveKWFhKAUK9ePSEpKUld75tvvpGs5+LiIty7d09dTyoVlkwmE+Li4kT7lmpPJpMJ69atU9fJyMgQ2rZtK6pXpUoVyeedV1J9yGtayIsXL4reZwsLC2Hv3r0a9ZKTk4X27duL9vfDDz9o1Lt8+bKoTp06dUT7/e6770T15s+fr1Fnzpw5ojp+fn7C3bt3Neo9fPhQ8PHxEdXdv3+/Rr2iSgvp5uYmDB48WBg8eLDQq1cvoUaNGpL7nTJlitZ2tX22c7sFBgYKly9fzrXfs2fPFm37wQcfqB9/+fKlYGxsLKqjLY2X1HPMLZWgPh06dEi0/27duuW6nVTaKl1uEyZMENLT07W2W9C0kOXLl1d/hrp16yaZklIulwurVq3S2of8pIUUBEE4d+6c5HYLFizQus2NGzdE9Rs1aiRZtyjTQrZv314YPHiwMGjQIKFdu3aCnZ2dqI6np6fw+PFjyXa//PJLUX1zc3Ph+PHjGvWOHz8umJubi+pKpeyU6ufbaSH1Pfblx+TJk/P0nTA1NRU+//xz4cWLF5LtafsdHjJkiGS6ydOnTwvffvutqFzqu5X9Wr+Z0ufnn38W1ZHJZMKrV6802hs2bJioXnBwsBATE6NR7+rVq6LUhkZGRqJjJ0Mel2zZskVj27cplUph8ODBova++eYbrdvoSirNsJ2dnTr1YWZmpuDs7Cyqs3btWq1t6jMt5K1btySPaTt27KiRnjEmJkaoVKmS5Huj676BrJTIqamp6nrr16+XrHfx4kVRm1L1zMzMhIiICHUdqRSc2bfffvtNXS8uLk4oXbq0qM6cOXM09qnvY0FB0P77+ssvv2jU++KLL0R17O3tRe0Jgu6fCdKPgqSFTE96LcyvFCDM8Cgt7Pf1LlA6yLdv27zLCjM8Sgt/1PtQyMzhWKyo9O7dW5DJZIKnp6fw119/Gbo7pKMjR44IzZo1E5ycnARjY2PB1tZWaNq0qXDw4EFDd42KSF7GOAbXiIiISqCffvpJ8o/SW7du5bvNhIQEyRPms2bNkqzfrl07Ud1atWpp1CmOwbW314A4cOCAZL3Zs2dr1MvIyJBcI0MqoCnVntT6Wfv27RPVs7W1lXzeeSXVh7wG177//ntRG8OHD5esGxkZKarr4+Mjqie1ttibJ4VVKpVQtmxZjcfNzc1FJz2l1uXZvn27ZN9+++03Ud1+/fpp1Cmq4FpuN09PT40grJT8BtcACGFhYTmeYBUEQahatapouwkTJmjUadWqlajOwIEDJdvz8/MT1a1bt27eXswCkFp37quvvsp1u/wG1xwdHUUnJ99U0OBabrcKFSoI//77b47PLb/BtVu3bkluN3nyZK3bvHjxQrKPRSU/a/IYGRkJ3bp107ouikqlElxcXETbDRkyRLL+0KFDRXVdXV1F9aT68nZwTd9jX36oVCrJwFNutzJlykiOP1JrvLZp0ybP/ZL6bpUuXVoUoEtJSZFcN+rt33M3NzdRnStXrkjue9SoUaK6EydO1KhjyOOSbC9fvhR27NghzJw5Uxg9erQwdOhQdbBe6riuQYMGubzquevQoYOo3b59+2rUkQrsNWvWTGub+gyuzZo1S1THxMREePTokai9vXv3Sr43uu5bW7tSn7XNmzeL6kntW+r3TGrtuKpVq+rUx6FDh2rUKYxjQanftkqVKonq3bx5U/I5v31MKAgMrhW1ggTXzi75TZjhUVqYX8ZZuOTvL1z2D9Db7YK/vzDn/9deu7R6RSE9eyJ61+VljGNaSCIiohLIzs5OsvztNE15cf78eWRkZIjKP/nkE8n6nTp1wtatWzXKzpw5A5VKBbm8eC7r6uzsjGrVqmmUaVujrkWLFhr3FQoFSpUqJUovl5CQoNO+3043BQBubm6isrfbe/nyJcaOHZtj2+XKlcPQoUN16kdeSKXzmzlzJmbOnKnT9nfv3sWTJ080Up/1799flFpo9erVGDNmDICs9aveTk3VsWNHjc+8UqmUTE+UlzWu8rIOSFGxtLTEV199pfdUfm/6999/ERISgpMnT0qmpLty5QouXLggKu/atavG/c6dO4tSR2pL4yU1XhVkrMorqbWMbGxsCm1/sbGxGDp0KF6/fq1Ok1dUSpcujREjRqBx48aF0r629Z60/SYB0q+1rutRGUpISAi+++47reui3L9/X/RbAOT8e/l2ysknT54gOjoanp6eOverMMa+7DSn2jg6OmLChAkaZTKZDLNmzULnzp0xffp07NixA2lpabnu+8GDB+jXrx8OHDigLouOjpZcs2/IkCG5tqeLTz75RJSu2szMDPb29qJ1Ct/8/Y2OjhalmAMgSpeXE11+Z4rquOTGjRv47rvvsGPHDp3WzMomtZZjXsTGxkqmGZb6TVmwYIFG2f79+/Ho0SO4u7sXqA+5OX/+vKisXr16ksdoTZs2hb29PV69epWvfYWFhUm26+bmJvq86Xp82bJlS1GZi4uLaP245s2bi+pJHQe8vd/COBaUIpUKW+q1yu5jTr87VHxlpqXh7G9Z3/VUQYX9yfn7Luni5OyZCPzoEyiKKL0sEb2fiueZLyIiIsqRs7OzZHlBFll/9uyZqEyhUGj9w1bqhKBSqRStA1OceHl5icq0rRFXtmxZUZmpqamo7O11jrTx9vYWlUmtJSK8td5dQkICFixYkONt8+bNOvUhr6Q+E3n19km/rl27itYvWr16teT/s729NlNsbGyeTg7q0q/iICkpCSNGjEDLli0lA925iYqKgpCVmQJpaWm4efMmRowYIaoXHR2NadOmSbaxdOlSUVm1atVQrlw5jbL27duLPr9xcXHYsmWLaHup8eru3bsFfg91JfW91fWk5dt69+6tfo0FQUBMTAx27NghWtMFACZOnFjkn7OYmBj07dsXffv2LZT2ta11pe03CZB+rYvz2pwAcPDgQQQHB2PPnj2Sj2sbG6V+NwDp30sAkms85aQwxr7cfl+WL1+uta3g4GBs3LgRL1++xP79+zFhwgS0atUqx/WVDh48qLHOk7bXoEKFCnl7YlpI/fYC0r+/b/6eF8bvn5SiOC65cOECgoODsXXr1jx/fgqyvhiQ9Zv+9rpwTk5OaNSokUZZvXr14OHhoVGmUqmwcuXKAu1fF1IBxJyC3nkJiL8tv5/HnOj6Gcrv56eovgu6HicDur82VPxc37ger58VzbHR6yePcXn1iiLZFxG9vzhzjYiIqATSthj3vn37tF45nx/GxsZaZ6EV9iLz2v5wjomJyXebUn3WtiCxvp9fqVKlRGVGRkZ63Ye+6WOx5rdPrFtZWaFz5874888/1WWRkZE4e/YsKlWqhI0bN2rUDwgIQIMGDQq9X0UlJCQEhw4dQmpqKv777z+MGzcO27dv16izf/9+jBo1SuerwqWYmJigXLlymD59Oh48eID169drPL569WrRTJrMzEzJ4KZSqZSc3WJnZyc6YbZs2TJ06dJFo6xWrVqimQuJiYmIiIhA3bp18/S88kMq8KOviwBKlSqFVq1awdfXFx988IHGY2lpadi4cWOuM4Pyqnfv3li2bBmSkpJw8eJFjBw5EidOnNCos2zZMlSrVg1fffWVXve9f/9+yXJtv0mA9GutbUZYUQoPD0doaCieP3+OHTt2YNiwYRrjQmpqKrp06YIrV66gTJkyOrWp7XdDX78nxXXss7CwQFhYGMLCwgBk/X4fPnwYI0eOxNmzZ0X1L168KBkQKAxSv71A7r+/RfVaF8VxyeDBg7XOOs3N2xf85NWyZctEZVZWVpKz7aUCQsuXL8eoUaMK1If8KKxj3Px+HnOi62cov8+pqL4LJfE4mfIu8ONO+KBD4WVoeJtMzs8QERUuBteIiIhKIA8PD1SqVAlXrlzRKF+zZg0mTpyYa+oVKVInoFNSUhATE4PSpUuLHouOjhaVGRkZwdHRMc/7lgrgaUsb9uYV71S4nJyccP36dY2ysLAwBAQE6NyG1MzH/v37awTXAGDVqlUICQkRpVr69NNPRds7OjrCyMhIdAV+7969RbPiiiszMzNUrVoVmzZtQrNmzXDw4EGNx+fMmYN+/frpZfZGvXr1RMG12NhYxMfHw9bWVl22a9cuyVkkly5dwqVLl3Tal1Qar5YtW+LHH38U1Z05c2aRBNf8/PxEZfq4Ev9N5cuXh6OjoyiQdOfOHb3u502WlpaoW7cu9u7di+DgYNF3dcyYMejcubPeAlmPHz+WDL5Wrlw5x7RtUq+1r6+vXvqkD05OTujXrx+8vLwQFhamEUyIj4/HyJEjsXbtWo1ttM3Ui46Olny9pX4vs/edFyVl7JPL5WjYsCG2b98ONzc3UYDmzd93ba/ltWvX8nUsoy9S741cLsfnn3+uc7AhP8dD+vbkyRPJtH49evTA8OHD4efnp/7s7N27VzJ1YH5pSzN89+5dUQpIbSIjIxEREZFjAL+gpI5x306p+CZt3+d3VWEdC9L7iSkaiehdw+AaERFRCfXNN9+IUn8lJyeje/fu2LVrV65XqCYnJ+PKlSsIDg4GkJX6zdjYWJSObvv27ejXr59o+7fXWwOAmjVr5mu9NWtra1HZy5cvkZSUBEtLS3VZSkoKNmzYkOf2SzIvL68CXzmeX7Vq1cKhQ4c0ysqWLYv58+frtH1mZiYUCvHhZq1atVCxYkVcvXpVXbZu3TpR4NTY2Bi9e/cWbS+Xy1GzZk1ERERolDdu3FhyzQ4pRZWSMDcKhQILFy5ExYoVkZmZqS5XKpUYPXq05Pcsr7SlY3pzfwByTP+mq+w0Xm/ONKhWrRpCQkJw+PBhjbqbN2/G4sWLMWDAgFzbvX79OhwdHXNMP6iNu7s7nJ2dNYI8Fy5cgCAIerkiH8ia5RQXFycqf/s1LgxWVlaYN2+eaJ21hIQETJ48WTRDMT+SkpLQqVMnyfXrpFKPvuncuXOispo1axa4T/rWqFEj9OjRQ5SGbt26dfj222811sXy9PSEq6srnjx5olF3+/btks9N6nvs6uqa5/RyhTH25fX35d69e9i/fz969eolmVLuTfb29jA2NhalBXwz6FS2bFm4u7uL1l2bP3++eiacIUi9xyqVCl26dEH9+vVz3T47dayhvb2GKZB1zLV8+XLR8drbM2ALSmrWWn7bKczgWrVq1UTf+yNHjoiOQYGsAGR+11srqQrrWFDfpGa5FZdjPSIiendxzTUiIqISqlevXhon+7Jlp7qSOqEJAK9evcLs2bMREBCgcTW+tbW15BXLY8aMEa3ltm3bNqxatUpUN78pKb29vUUnuVUqFebOnatx/7vvvitQWkjKG6n3c+nSpZg3b57WoMGzZ8+wfPlyNG3aFFOnTtXa9tvrqD179kx0Arpt27ZaZ3Z06tRJVDZ06FCEh4dr3WdkZCRmzJiBypUr4+jRo1rrFbWAgAD06tVLVL5t2zacP3++QG3fvn0bv//+u6jc1tYWDg4O6vuxsbHYsWNHgfaVTSpIN2PGDMmTa59//jlGjBih9WTlpUuXMGDAAAQFBYkCGXnRsGFDjfsvX77EzZs3893em1QqFX744QfJk3g+Pj562UduGjVqJFrDCAAWL16Mx48fF6jtPXv24MMPP8Tx48dFj9WsWRPdu3fPcfu3A0EAEBoaKll32bJlkMlkGjdtdQvD+PHjJT+n48ePF5V17NhRVPbrr7+Knu+pU6cwa9YsnbbXhaHHvri4OAwYMABeXl4YOXKkOlD9tszMTIwdO1YUWJPL5aJjl7dTyQJZAcnhw4dLBnSvXr2K0aNHF+h56ELqN7Bnz55aZ/IKgoALFy5g4sSJ8PPzkwxsFTUTExNRWVJSkmj827dvH3755Re97VdbmuH8WL9+veTnQF/atGkjOgZNSEjAV199pTGux8bGYuTIkYXWj+KqMI8F9UnqQr1r164Vyb6JiOj9xZlrREREJZRcLsfWrVtRu3ZtPHz4UOOxU6dOoUaNGihfvjyqVKkCW1tbxMfH4+bNm7h06ZLWKzknTZqE3bt3a/yx/OTJE1SuXBlNmzaFi4sLbty4IZqBAgBlypTBoEGD8vVc7OzsULVqVVEgYfTo0Thy5Ag8PDxw4sQJUVoayptdu3bhxYsXudabPn06zM3NUa1aNXTp0gXr1q1TPyYIAoYMGYLJkyfjww8/hLOzMzIzMxETE4P//vsPUVFR6hOtderU0bqPnj174rvvvkNaWprWOp999pnWxwYNGoS5c+dqzHZ79eoVGjVqhPLly6NChQooVaoUkpOT8ejRI1y7dk3vqQD1afTo0VixYoXoRNX48eOxbds2ndoYN26c+uRSeno6oqOjER4eLpqNCgDt27fXOJm4Zs0a0Ulwe3t7PHv2DMbGxlr3eevWLfj7+2uUSaXxqlGjBpYsWSKabSsIAmbOnIl58+ahTp068PLygpGREWJiYnD+/HnR2JZf7dq10/gcA8Dx48fzlNYKyBpb31xD7cWLFzh79qxk+ke5XI62bdvmr8P5MHbsWFF60dTUVEybNk3jQoWcZD+3lJQUPH/+HKdPn5ZMFQpkzQjcsmVLrrOV354NU758edFnprjw8fFBjx49RDNutm/fjvPnz2sEhUaPHo3ly5drrCX0+vVr1KtXD40bN4aXlxeio6Px77//in5zra2t8f333+erj8Vl7Hv69CmmT5+O6dOnw9bWFtWrV4erqyssLS3x4sULHD9+XHK/zZs3F62t9P3332PZsmWitKqzZs3C8uXL0aBBAzg5OSEhIQGXLl3C9evXERQUhClTpuj9eb3phx9+wPLlyzXWK4uOjkaVKlVQtWpV+Pv7w87ODq9fv8b9+/dx9erVYjerKTAwEJaWlkhKSlKXqVQq1KhRA82aNYOtrS2uX7+OU6dO6XW/u3fvFr3/RkZGePToUY4zkBMTE+Hk5KQRTIuLi8OWLVskg7D64Ovri48++gj//POPRvnSpUtx5MgRhISEICUlBXv27Cl2729RKMxjQX2S+l2ZO3cuIiMj4enpqZ7Z9v333+eYypiIiCgvGFwjIiIqwTw8PBAeHo5PPvkEFy9eFD0eGRmJyMhIndsLCgrCkiVL0K9fP40r0VNTU3M8wW9tbY1t27ZJLkavq2HDhkmmtdqzZ4/G/dKlS3P2Wj6dOXMGZ86cybXeTz/9pH4vFy9ejFu3bolmQj579gzbt2/Pd18cHBzQoUMHUcAjm6enJ5o0aaJ1ezMzM+zYsQP169cXnezK6+e+OPD19UX37t1Fs762b9+Oc+fOoXr16rm2sWLFCp325eDggEmTJmmUSaXv6tChQ46BNQAoV64cgoKCRDM5pNJ49enTBzKZDIMHD9Y40QtkBQPfTjulT+3atVNfZJBtw4YNkilvc5KXz9bw4cOLdG2xkJAQyfSbS5YswahRo3Ra80bXdZBq166NNWvW5NpmRESEaO0iqVSvxckPP/yAlStXigJibwe6XVxcsHHjRrRu3VojMK1UKrFv3z6t7RsbG2PDhg35Xk+sOI598fHxosCuFHt7e8lZfI6Ojti2bRuaNm0qGhtiY2OxefNmvfU1L5ycnLB582a0aNFCdCHIhQsXJNcTK25MTU0xePBg0ay0pKQkbNq0SaOsTZs2Bfpdf5PUb0pISEiuqX2tra3RrFkz0Uz2ZcuWFVpwDchKQ3r06FHRxQR37tzRuHjCxsYGdnZ2xWJWYlEqrGNBfWrbti2mT5+uUaZUKrF7926Nsv79+zO4VgIolUqcPHkSW7duxaNHj5CcnAwLCwu4u7ujXbt2qF27tmQqUCKiosa0kERERCWcn58fIiIiMH78eNHV4DmxsrJCpUqVROV9+vTBrl27dP7Ds2bNmjh79iyqVKmi876l9OjRI9cT3Z999lmhX6lOmqytrXH48GEMGjQoT3/Eenh4ICgoKMc6b6eGfFO/fv1ynRFToUIFnD9/XjIdXk6qVKlSLE+s/PDDD5KvsVRKuvyqUqUKjh49ijJlyqjLrly5Ipl+snPnzjq1KZUySlsar969e+PcuXP46KOP8rQ+Y7ly5TTWacorc3Nz0ay5/fv3F8qMHlNTU4wdOxY///yz3tvOzdixY0VlqampekvL5eXlhRkzZuDIkSPw8vLKtf7b6YPNzMzyHNAsan5+fujWrZuoPDvQ/aYmTZrg2LFjOs+ALFeuHI4ePYpmzZoVqI+GHPvs7e0RGBiY5+0qV66MgwcPan2t6tSpg7Nnzxbq2lr50bBhQ5w+fRpVq1bVeRuZTIa6devCxsamEHumu59++inHWbQymQyjRo3CN998o5f9aUszXJDflP3794vW5dMnFxcXhIeHa/w2vs3JyQk7d+6UrJPbOsclXWEeC+pLvXr10KNHjyLZFxUepVKJ1atXo0OHDvj6668RHh6Omzdv4uHDh7h58ybCw8Px9ddfo0OHDli9ejVUKpWhu6w3hw4dgkwm0+txvz517twZQUFB+VpPNDQ0VKfjxneVTCZDnz59DN2N91paWhrc3Nzw9ddf671tzlwjIiJ6B5iammLcuHEYOXIktm7disOHD+PUqVN4+vQpXr16BZVKBRsbG3h7eyMoKAhhYWFo2bKl5PoEQFbaprt37+Lvv//Grl27cPbsWTx79gzJycmwsbGBh4cHatWqhU8++QRhYWF6ex5//vknmjRpgiVLluDChQt4/fo1nJ2dUb9+fQwaNAj169eXvBqaCpelpSUWLlyI77//HitWrMDRo0dx/fp1vHz5EqmpqbCysoKLiwv8/f0RHByMRo0aoVatWqI1TN7WqFEj+Pj44O7duxrlcrlc5xPwXl5eOHDgAM6ePYu1a9ciIiICd+7cQVxcHFQqFaytrVG2bFmUL18e9erVQ5MmTYptSrpy5cqha9euooDEjh07cPbsWdSoUSNP7ZmZmcHa2ho+Pj6oWrUq2rZti2bNmomCWlJrpJUqVUrnE/effPIJxowZo1GWUxqvgIAA/PPPP7h79y62bt2Ko0eP4tq1a4iNjUV8fDxMTEzg6OiIgIAABAcHo0WLFqhTp06un6fcfPPNN1i4cKF6lpFSqcSaNWswbNiwfLdpZGQES0tLlC5dGoGBgQgNDUWnTp3g4eFRoL7mV6NGjVCvXj0cO3ZMozx79lpugRWZTAaFQgFTU1PY2trC0dERnp6eqFixIkJDQxEWFqZzUDQ9PR3r16/XKOvbt6/WdRSLkzFjxmDNmjWSs9fenqVRs2ZNXL9+Hdu3b8eWLVvUv72JiYnqsTE4OBht27ZF+/bt8xRUzomhxj5PT09cu3YN0dHROHz4MM6cOYPr168jOjoaMTExSE5Ohlwuh42NDTw9PVG1alW0b98ezZs3z/WkfPny5XHy5EkcP34cf//9NyIiInDv3j3ExcXBxMQEzs7O8PT0RGhoKFq0aFHg56KrypUr4/z58zh48CA2bdqEU6dOITo6GvHx8ZDJZOrnGhgYiAYNGqBp06Y5BmmKmrGxMbZs2YJVq1bhr7/+wsWLF5GcnAxnZ2fUrl0bgwYNQmhoqN5mD69du1aUZlihUOCjjz7Safs2bdrA1NRUY7agSqXCypUrMWrUKL30UUpgYCCuX7+O2bNn459//sHt27cBZH3X2rVrh2HDhsHR0VEyXXHp0qULrV/FRWEdC+rTihUr0KhRI6xevRqXL1/Gq1evtK4LR8VPamoqfvzxR/UaoioTE6T5+SDT1RmCsTFkGRlQPHkK09tRePz4MX799VdcvHgRkyZNMkiAW6lUYvny5Vi5ciUuX76s/rs1JCQE33zzjeRFGX369MHy5csRFRVVooJN586dw4YNG7Bu3boi/U4T6YupqSmGDx+OH374AcOGDYOnp6fe2pYJ+Qk5ExERERERlTBDhgzBvHnz1Pc9PT1x69atXNNfUt4tXrwYAwcOVN+3sLDArVu3dEpPSURUHJ0+fRrBwcEaZXK5HM+fPy/Q7GqikkalUuHGjRsAsi6aKuiFI0qlEqNGjUJ4eDgEuRzJNaoizc8HUEjMCcnMhOntu7A4ewEylQoNGzbEtGnTijRNZFxcHNq2bYujR4/Czc0NrVu3hoODA27cuIFdu3YhPT0d06dPx/DhwzW2yym4dujQITRs2BDjxo0rdrPX2rdvj3PnziE6Ojpf7/X9+/eRkZFRpOnSixOZTIbevXvzImEDyw6A9+7dGwsXLsyxbl7GOKaFJCIiIiKi98LYsWNhb2+vvh8dHS05c48KJiMjQ5TCd8SIEQysEVGx9d1332Hr1q2SKY2BrJkbUrOxQ0JCGFgjKqB169apA2uJYaFIK+8vHVgDAIUCaeX9kRgWCkEuR3h4uGimfGESBAHdunXD0aNH0a1bN9y+fRu///47pk6dik2bNuHixYsoU6YMRowYgb///rvI+lVYHj9+jB07dqBTp075DqKWLVv2vQ2sUfFhZWWFVq1aYc2aNUhJSdFbuwyuERERERHRe6FUqVKi9cemTJmCjIwMA/Xo3bR8+XJER0er7/v4+OD77783YI+IiHJ24MABtG/fHo6OjqhXrx569eqFQYMGoUePHggKCkKNGjUQFRWlsY1MJuNawEQFpFQq1cGx5BpVkenirNN2mS7OSK6RlXpx/fr1olTOhWX37t3YvXs3KlasiGXLlsHc3Fzj8fLly6uDasOHD1cfY3p5eakv6PL29oZMJtO6xtrRo0dRr149WFhYwMXFRaOdN2VmZmLu3LmoWrUqLCwsYGtrixYtWuD06dOiul5eXvDy8sKLFy/Qr18/ODs7Qy6X4969ezk+3+w02VKpfWNjY/Htt9/C398f5ubmsLe3R+XKlTFy5EiNem+vubZs2TL185e6vb0+2fXr19G1a1e4uLjA1NQUfn5+GD9+vEb6YH2JjY3FyJEj4e/vDzMzMzg5OaFhw4aiAG58fDxGjBgBb29vmJqaws3NDZ9++qle1ge9fv06evToATc3N5iamqJMmTL45JNPcObMGY16N2/eRJcuXeDk5ARTU1P4+/tjwoQJGheJHDhwADKZTJTCP9v8+fMhk8mwevVqjfJdu3ahcePGsLOzg7m5OWrUqCGqA2TNxpTJZLh9+zYmTZoEX19fKBQK9Sy948ePo3///ggICIClpSVsbGwQEhKCnTt3SvYnISEBgwcPhrOzMywsLFC7dm0cOHAA48ePh0wmE31e8/IdAICPPvoI8fHx2LZtm+Tj+cE114iIiIiI6L0xcOBAjXSFpH/9+/dH//79Dd0NIqI8S05OxvHjx3H8+PFc686fPx+1atUqgl4RvbtOnjyJx48fq9dYy4s0Px+YX7yCR48e4eTJk6hXr14h9fJ/VqxYAQAYNmyY1rTiwcHBqF+/Po4ePYqDBw+iWbNm+Prrr7Fs2TJcunQJQ4cOhZ2dHYCswNObTp06hZ9//hktWrTAoEGDcODAAcyaNQuCIGDWrFnqeiqVCh9//DG2bduGGjVqYMCAAUhMTMSmTZvQoEED7Nu3Dw0aNNBoOy0tDY0aNYIgCOjatSsSExNhYmKS4/M9dOgQFAoFqlWrplEuCAKaNm2KCxcuoHnz5ujQoQOSk5Nx48YNLFq0CL/88ovWNqtUqYJx48aJyo8dO4YDBw7AwsJCXXb48GG0bNkSMpkM7du3h4uLCyIiIjBhwgScOXMGO3bs0Ns6cI8ePUL9+vURFRWFBg0aqAMxZ8+exW+//YbOnTsDAJKSklC/fn1cuXIFDRs2RJcuXRAZGYmlS5diz549OHXqVL7XXz5w4ADatGmDzMxMtGvXDn5+fnjy5AkOHz6MnTt3ombNmgCAK1euoH79+khKSsInn3yCsmXL4uDBgxg/fjyOHDmCffv2wcjICKGhoXBxccH69evx008/ifa3du1aWFhYoH379uqyGTNm4Ntvv0XZsmXRqVMnmJmZYffu3ejRowcePnyI7777TtTO4MGDcfnyZbRq1QrW1tZwds4Kks+bNw+nTp1C3bp10aFDB7x69Qrbt29HmzZtsGbNGo0Z4ZmZmWjevDlOnjyJOnXqoEGDBoiKikLLli1F3xMgf9+B7N/s8PBw9ftZUAyuERERERERERER6cDLywsLFy5EixYtDN0VohJv69atAKB9jbWcKBRI8/OG+fUb2Lp1a5EE1yIiIgCIg2JvCwkJwdGjRxEREaEOrl28eBGXLl3C119/LVpzLduePXuwY8cOtGrVCkBWQKxatWpYvHgxpk6dClNTUwDAokWLsG3bNvzwww+YNGmSOsA0duxYVKlSBZ9//jmuXbumEXh6+vQpgoODsWHDBp3XG46IiED58uVFM/SuXLmC8+fPY9iwYRpBPyBr9ldOqlSpgipVqmiU3bp1C3PmzEGZMmXUgbe0tDR0794dNjY2OHXqFMqWLauu/8033+DXX3/F+vXr1QGauLg4zJ49W6fnld2PN4NKgwYNQlRUFObNm4cvv/xSo+6bM9KmTp2KK1euYPjw4ZgxY4a6fNGiRfjiiy8wfPjwfKUqTUlJQffu3aFSqXDy5ElUr15d/ZhKpcKzZ880+po9A6tNmzYA/peydN26dVi8eDEGDRoEIyMjdOrUCXPnzsWZM2fUwTkgKz3+yZMn0alTJ1haWgIALl++jO+++w5hYWHYunWrOtCZkpKCsLAwjBkzBt27dxcFD2/fvo2LFy+qg2rZfv75Z5QtW1bjc/jrr7+ibt26GD16tEZw7c8//8TJkydF69OtXbsW3bp1E71e+fkOeHl5wcHBASdOnMjl3dAd00ISEREREREREdF7a8eOHVi1ahX69u2LoKAg2NvbQ6FQqNOC1axZEwMHDsT27dtx+/ZtBtaI9CQ7aJHpqls6yLdlurpotFPYsgMc7u7uOdbLfvzNgIguGjVqpA6sAYCpqSk6d+6MpKQk3Lx5U12+aNEiuLm5YcKECRrBA09PT/Tv3x///fcfrl69Kmp/6tSpOgfWUlNTERsbCycnJ6113pxlli2v61AmJCSgbdu2SEtLw+bNm9UBmu3bt+PRo0cYN26cRmANgPp5b9iwQV0WFxeHCRMm6HzbsmWLetsnT55gx44dqFatGgYPHizq45vv96pVq2BlZYUff/xRo87AgQPh5+eHTZs2ISkpKU+vAZAVaH727Bm++OILjcAaAMjlcri6ugIA7t27h+PHj6NevXrqwBrwv1TFcrkcK1euVJdnB6bWrl2r0ea6devUAblsixcvhkqlwrx58zTeW3Nzc4wePRqZmZnYvHmzqO8jRowQBdaArM/j2zMLLSws0KtXL0RFRWmkeVyzZg3kcjkmTJigUb9r164IDAwUtZ3f74CzszMePnwoKs8vzlwjIiIiIiIiIqL3louLC7p3747u3bsbuitE75Xk5GQAgKBjwOdt2dtlt1PSBQUFicrc3NwAZAWPgKy0hNevX4evry8mTZokqn/9+nUAwI0bN1CpUiV1ubm5OT744AOd+/Ly5UsAgL29veixwMBABAYGYsqUKbh8+TLatGmD0NBQlCtXTuf2gawZWd26dUNkZCRWr16tEVTKXjfr3LlzkmvTmZub48aNG+r7Xl5eEAQhT/vPdu7cOQiCgMaNG+eYZjIhIQHR0dGoXbs2bG1tNR6Ty+WoV68ebt++jevXr2vMEtPF2bNnAQBhYWE51rt8+TIAoH79+qLHvL29UbZsWVy6dEldFhwcDB8fH/z999+YMWMG5PKsuVZr166Fvb09mjdvrq57+vRpKBQKrFu3TtR2TEwMAGi85tneThuaLTU1FbNmzcKGDRtw69YtUdDxyZMn6lmcly9fhqurKzw9PUXt1KpVS/25BvL/HQCyPs+RkZFQqVTq16IgGFwjIiIiIiIiIiIioiKVPTtGlpGRr+2zt5OaQVUYnJ2dER0djUePHsHHR/sacY8fP1bXzwsbGxtRmeL/02UqlUoAWUE2QRBw+/Zt0SyfN70dyChdunSe+pKdCjI1NVWyT+Hh4RgzZgz++ecfbN++HQBQvnx5TJs2De3atdNpHz/88AN27tyJb7/9VpT679WrVwCAP/74Q+v2+ZkhJiU+Ph7A/wKZ2iQkJADQ/r5ml2fXM1Qf7t27B6VSCSMjIwBZs78mT56Mo0ePIiQkBJGRkbh06RL69++vse7eq1evkJmZmafPFQCtsxvbtWuHffv2oXr16ujduzccHBxgZGSEixcvYuvWrUhLS1PXTUxM1Jou9e328/sdALJSXJqamuolsAYwuEZERERERERERERERczd3R03b96E4skzZLjnHFSQonjyVN1OUahVqxaio6Nx6NChHINrhw8fVtfXN2trawBZM5z279+v83Y5zciSYmdnB4VCoZ7B9jYnJycsXrwYv/32Gy5evIhdu3bh119/RceOHXH27FnJWXhvWrduHaZNm4ZmzZph6tSposezn+exY8dQt27dXPtbkDXXsmehZQdFtckOfmpL95ldLhUkzc2bfXh7Tbq89sHCwkIdWAP+F1xbu3YtQkJC1Ckiu3btqrGttbU1TE1NkZycnKfgk9Rn6/Tp09i3bx8+++wzLF68WOOxn3/+Wb3e4pv7zp4d97bnz5+L6gJ5/w4AWQHEUqVK5WmbnDC4RkRERERERERERERFql27dggPD4fp7btIqVIJUOThVHVmJkxv31W3UxR69uyJ9evXY/bs2ejVq5d6VtmbTp8+jaNHj8LDwwONGjVSl2cHK1QqVYH6YGNjA39/f1y+fBmpqakwMzMrUHvayGQyBAYG4vbt2znWk8vlqFatGqpVqwYvLy/07NkTe/bsyTG4dv78efTr1w/lypXDunXrNAJB2bLTKp46dUrn4FpOs5je1rt3b3VwrXr16pDJZDhw4AAEQdAaiLSxsYGXlxeuXLmC+Ph4jdSQKpUKx48fh0KhkFwjLDc1atQAAPz7779o2bKl1nqVK1cGkBV0fFt0dDQePHiADz/8UKO8QoUKqFy5MjZu3Ih58+Zh7dq1cHV1RWhoqEa9mjVr4sKFC7h48aLWVI+6uns367vZtm1b0WPHjx8XlVWuXBnHjh1DdHS0KDXkqVOnNO7n9zuQkpKChw8fokmTJro+jVzpZ/4bEREREREREREREZGOateuDTc3N8jT09WBMl2Z3r4LeXoG3N3dUbt27ULqoaaWLVuiadOmuHLlCvr16ydKmXjz5k107twZgiBg5syZMH5jLTkHBwcAwKNHjwrcj0GDBuH58+cYPnw4MjMzNR4TBAFHjhwp8D4AoG7duoiJiUF0dLRG+b1793D//n1R/ewZRqamplrbfPbsGdq3bw9jY2Ns3boVdnZ2kvXat28PV1dX/PTTT7h69aro8ZiYGPz333/q+9lrrul6W7ZsmXpbV1dXtG7dGufPn8fChQtF+3pzRluPHj3w+vVrTJ48WaPOH3/8gVu3buGjjz6CpaWl1uevTbt27eDs7IyFCxfi3LlzGo+pVCo8ffpU/Tzr1auHo0ePYteuXeo6giBg9OjRUCqV6Nmzp6j9rl27IjY2FlOnTsWtW7fQuXNn0ey0gQMHQi6XY/DgwYiNjRW18d9//4lmkWlTpkwZAOJA2qZNm9RpRN/un0qlEgVI169fj2vXronq5+c7cP78eWRmZkquV5dfnLlGREREREREREREREXKyMgInTt3xq+//gqLsxegtLNFpkvu65QpnjyFxdkLAIDOnTtLznwqDDKZDGvXrkWbNm2wcuVKHDx4EK1bt4aDgwNu3ryJHTt2ID09HdOnT0enTp00tg0NDcXMmTMxcOBAdOjQAebm5mjQoAEaNGiQ534MGTIEhw8fxsKFC7F//36EhITA3t4eDx48wKlTp/D48WPJtdLyqm3btli0aBEOHjyIvn37qssvXryIjh07onbt2vjggw/g6OiIGzduYPv27XB2dhatn/amCRMm4MGDBwgNDcX69etFj2enazQ3N8e6devQqlUrVK1aFS1btkRAQAASExNx+/ZtHD58GBMnTsQHH3xQ4OcJAIsWLcKVK1fw5ZdfYsOGDahVqxZev36Nc+fOwczMDOHh4QCAUaNGYevWrZg+fTrOnTuH4OBgREZGYsuWLXBzc8PMmTPztX9zc3OsWrUKbdu2Re3atdG+fXv4+fnh+fPnCA8PR8+ePTF+/HgAwMKFC1G/fn20a9cOnTt3RpkyZRAeHo5Tp06hYcOGGDBggKj9rl27YvTo0Zg0aRIASL5H1apVwy+//IJvv/0W/v7+aN68OcqUKYNnz57h6tWrOHv2LE6ePKl1jbU3BQcHo0qVKvj5559x7do1lC9fHteuXcOePXvQrl07UVrITz/9FMuWLcPSpUtx69Yt1K9fH1FRUdi8eTOaNm2Kffv2aQQD8/MdOHjwIACgTZs2ufZfVwyuEREREREREREREVGR69KlCy5evIjw8HBY/3sIyTWqIs3PRzpF5P+ngrQ4ewEylQqNGjVCly5dirS/Dg4OOHz4MJYtW4ZVq1bh77//xuvXr+Hs7IyOHTti2LBhqF69umi71q1bY+LEifjzzz/x888/Q6lUYty4cfkKrsnlcvzzzz/466+/8Ndff2H9+vXIyMiAm5sbatSogc6dO+vjqaJp06YoW7Ys1q1bpxFcq1GjBoYPH46DBw9i06ZNSEpKgoeHBz7//HN89913OQZfkpOTAQCHDh3CoUOHRI+/ma6xQYMGuHDhAqZNm4Z9+/Zh9+7dsLOzg5eXF0aPHp1jEC+v3N3dcebMGUyePBlbt27FyZMnYWtri4oVK2LQoEHqepaWljhy5AgmTZqEf/75B0ePHoWjoyP69OmDiRMnwsPDI999CAsLw6lTp/DTTz8hPDwcW7duhZOTE+rUqaMREKpUqRJOnTqFsWPHYu/evYiPj4enpyfGjRuHUaNGSQabPT09Ubt2bZw4cQK+vr7qtJtvGz58OKpVq4ZZs2Zh3759iI+Ph7OzMwICArBgwQJUqlRJp+eiUCiwc+dOjBgxAgcOHMDBgwdRuXJlbNu2DTExMaLgmrGxMfbs2YPvv/8e//zzD86dO4egoCDs3LkTW7Zswb59+9RrrQH5+w6sW7cOH374ISpWrKjTc9CFTBAEQW+tEREREREREREREdE7SaVS4caNGwCAgIAAUWq5/EhNTcWPP/6onh2kMjFBmp83Ml1dIBgbQ5aRAePHT2FyJysVJAA0atQIEydOLLQ1xyjL9OnTMXr0aNy9e1ed6o+oKIWEhOD69euIiYnJdxunT59GcHAwVq5ciR49euRYNy9jHINrRERERERERERERJSrwgiuAYBSqcT69euxbt06jTWu3ubu7o7OnTujS5cuets3aZeSkoJy5cqhffv2mD9/vqG7Q++wp0+fwsXFRaNs48aN+OSTT9C3b1/89ddf+W67Xbt2iIqKwsWLF3MdN/IyxjEtJBEREREREREREREZjJGREbp164bOnTvj5MmT2Lp1Kx49eoTk5GRYWFjA3d0d7dq1Q+3atYtsjTXKWgts+fLlOHv2LARBgEwmM3SX6B3Vs2dPJCQkoHr16rCwsMCVK1ewb98+ODo6Yty4cfluNy0tDdWrV8fo0aP1HpDnzDUiIiIiIiIiIiIiylVhzVwjovfbH3/8gSVLluDWrVtITExEqVKl0KRJE4wfPx4+Pj5F1g+mhSQiIiIiIiIiIiIivWJwjYjeZXkZ4zj6EREREREREREREREREemIwTUiIiIiIiIiIiIiIiIiHTG4RkRERERERERERES5kslk6v+rVCoD9oSISP/eHNfeHO+kMLhGRERERERERERERLmSyWQwMTEBACQlJRm4N0RE+pU9rpmYmOQaXFMURYeIiIiIiIiIiIiIqOSztrZGbGwsnj17BgCwtLSEXM45HERUcqlUKiQlJanHNWtr61y3kQmCIBR2x4iIiIiIiIiIiIio5FMqlbh//z5SU1MN3RUiIr0zMzND2bJlYWRklGM9BteIiIiIiIiIiIiISGdKpRKxsbFITExEenq6obtDRFRgJiYmsLa2hqOjY66BNYDBNSIiIiIiIiIiIiLKJ0EQwFPMRFSSyWSyXNdYE23D4BoRERERERERERERERGRbrjSJBEREREREREREREREZGOGFwjIiIiIiIiIiIiIiIi0hGDa0REREREREREREREREQ6YnCNiIiIiIiIiIiIiIiISEcMrhERERERERERERERERHpiME1IiIiIiIiIiIiIiIiIh0xuEZERERERERERERERESkIwbXiIiIiIiIiIiIiIiIiHTE4BoRERERERERERERERGRjhhcIyIiIiIiIiIiIiIiItIRg2tEREREREREREREREREOmJwjYiIiIiIiIiIiIiIiEhHDK4RERERERERERERERER6YjBNSIiIiIiIiIiIiIiIiIdMbhGREREREREREREREREpCMG14iIiIiIiIiIiIiIiIh0xOAaERERERERERERERERkY4YXCMiIiIiIiIiIiIiIiLSEYNrRERERERERERERERERDpicI2IiIiIiIiIiIiIiIhIRwyuEREREREREREREREREemIwTUiIiIiIiIiIiIiIiIiHTG4RkRERERERERERERERKQjBteIiIiIiIiIiIiIiIiIdMTgGhEREREREREREREREZGOGFwjIiIiIiIiIiIiIiIi0hGDa0REREREREREREREREQ6YnCNiIiIiIiIiIiIiIiISEcMrhERERERERERERERERHpiME1IiIiIiIiIiIiIiIiIh0xuEZERERERERERERERESkIwbXiIiIiIiIiIiIiIiIiHTE4BoRERERERERERERERGRjhhcIyIiIiIiIiIiIiIiItIRg2tEREREREREREREREREOmJwjYiIiIiIiIiIiIiIiEhHDK4RERERERERERERERER6YjBNSIiIiIiIiIiIiIiIiIdMbhGREREREREREREREREpCMG14iIiIiIiIiIiIiIiIh0xOAaERERERERERERERERkY4YXCMiIiIiIiIiIiIiIiLSEYNrRERERERERERERERERDpicI2IiIiIiIiIiIiIiIhIRwyuEREREREREREREREREemIwTUiIiIiIiIiIiIiIiIiHSkM3QEiorxwcXFBUlISypYta+iuEBERERERERERFYn79+/D0tIST58+LXBbbdu2xZ07d/TQK/3z9fXFtm3bDN0NolwxuEZEJUpSUhIyMjIM3Q0iIiIiIiIiIqIik5GRgaSkJL20defOHdy+/R/8vIz10p6+3L7Hc35UcjC4RkQlSvaMtWvXrhm4J4UjMzMTCgWHZiLSH44rRKRvHFeISJ84phCRvr2r40qFChX02p6flzGuHPbUa5sFVSkk2tBdINIZ11wjIiomBEFAdHQ0BEEwdFeI6B3BcYWI9I3jChHpE8cUItI3jitEVFTevRA+EVEJJZPJ4Ovra+huENE7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qv92yAKAVRRteRWu80JaSREKzp3Dho8+RK+H/sb33g343mPuAXzvVacx771dB/bCOqgFyv77ne96Go0GWk3Fn05mi6XKCUvVrWcym2u8NplWq4Xmv7+L+q5nNJlsvzMx0h+bN2xH7249APC9Vx1Xeu8x9/5H6vfe8dPH4Ne+YnvlBgPEGtqj9Pr/nThpMFS/TwECPPT/nUZRFGEor5oVQMVsKR4e+v+uZkV5eXm166kEFXT/PfFStFpRbrRfTx8iYPf+nejcqYvk771Lly7Bq5kVFosFJmP1eabWaKDV/jf3zBaYa8k9TeV6pprzTKPVQqP5b+6ZzLDYrWcA/vtyanVaW16YTCZYzPZ5ofEtw759+9CqVStFv/eYe1Ux9/jeq89779iRveh/7/+y2mq11vhcVSo1dDrtf+uzwmT633oawYDK+FWr1dBqK9er+XucWn1D7plryb3K74W1fI/TaOxzr0VzC37bkoxjxwbYrdeQ954jWEVln1hGpGScFpIU7fovW2+++SZ27tyJlStX4sCBA8jNzUVycjL+9re/OWTfb775Jo4cOYItW7Zg9+7ddh1nixYtsg22rV69Grt27bIt+7//+z+kpKRg1apVtqkYK3322We1zq8cFxeHY8eOYfv27di8eXONF6vX6XTYtm0btm/fjj///BMjR460LcvIyLCb5vHVV1+1HaiOjo5GWloaNm7ciPXr1+P48ePw9fUFUPFl+Z133qn1NXnjjTeQlpaG33//Hampqbjnnntw9OhR/PTTT7Z1EhIScPLkSaxfvx6pqal2029evHix1sHFm50oiigoKOA0S+Q2LCaTrWstxtMX6gZOeq8WBMR4+gBmEzJ+/jcsJl57raGYK0T1U15ejrz8a1D5e8ldSr2o/L2QX1hQ48EhR2KukCu5dPkivJu51vXWKnkFeeDqteoHAZrKaDRC0FY94UkWIqC71rpe00ICgEor1nggm4hcm9VqRW7uZUSEN+1wtSgC5y53VNy0kBHNVci9cqXay8YQkWsSRP5VRAo2fvx4W8dUYmIinnjiCSQmJqJt27a2M5muFx0dbTtLatCgQdi6davd8usvvP7AAw/YXTPs+sf6+/vj0qVLdgNq9957r901zXbt2oW+ffvisccewyeffGJXs+66qcsuXrxoN/j2r3/9C1OnTgVQcc21r776yrbshx9+wF/+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K6+EKIrQ6/W45JJL0LdvX0RHR6OmpgZpaWm2ebWaK05YrVZceumlGD58OPR6PXbv3t0gvtaqP77xhRdeiAEDBkAul+OOO+7A5MmTW70uuVyOefPm4Z577rE99sgjj+Ddd99F7969UVlZid27d2PChAm4+uqrAQBDhw7Fjh07AAApKSno1asX4uLisG/fPuTn57d620258MILMXToUNtndPjwYSQkJGDQoEFITU21K0p2xKJFi/DII48gODgYvXv3hr+/P8rKyuzmXgOaH0969uzZWLZsGQIDA5GSkmI3t999991nK4xdeeWVuOCCC/DHH38AAFauXIlu3bph4MCB8Pb2xpkzZ3Do0CG71wNAYGAgnnjiCbzyyisAaq9qmTp1KhITExEfH4/CwkLs3bsXDzzwACZMmNDie+7s766+++67z26ewrCwMLz//vt4//337ZabNm0apk2bJvn261xwwQUYOXKkrXPv0KFD6NmzJwYOHIgjR440mJPtfNdc1xqAdp2cjdR4IbO6wta91qcVc68R0flBEIRWzwXhbOFdu0L9R+cPE6iOiYHqrwPQV9dA1LV/btJzCVax4VxYErNWVsOnsAQXdXCOWFcRHByMfvEJ2JN5Gur4CGeHYyNXKBDo74+CshIIfroWlxdyCqEJ9YOiFctKRbSKMG9KxaO33mU3jLdMJkNkRCTOFlRA3dWvmTV0kABkaytbXq6VjAUV6BbZrU1DYxOR53CnYxUicg/MK0TkKJL8gpk0aRIefPBBu8d2796N3377DRqNBldeeWWjr5s8eTI+/PBDu5MRhw4dwurVq7Fp0yZbYQ1ofr6nq666ClqtFjt27GhQWJs5c2aDzqbmTJ061a57LTs7Gz/99BOWL1+O48ePt3o9de6++27MmTPH7sdi3XCBv/32W4N55F5++WW7Lru0tDSsXbsW+fn5eOmll9q8/cZ89dVXdpNyFhYWYuPGjThx4gRuueUWSbZRp6CgANu3b8dPP/2ErVu32hW4pk+fjsGDBzf6uqFDh2L48OE4ePAgtm7davc5DRs2zK7YKggCVq5cabeu0tJSbN26FatXr8bu3btt263/o33u3Ll2xU+gdljDX375BSkpKXbdaC1xxHd3rrqOwzrZ2dlYvnx5g1v9oT87w5dffmk3gWtBQQE2btyI3Nxc3HfffXbLqlSqTo/HVbXUtQa0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ykrmzZvH+PHj693u2Vx++eWO/7fb7dx8883k5eU5nlNVle+//97xtzwzptdee82xvN1u5/HHH3d6/fR9qLWJiYlx/P/q1av5/fffAdi1axcvvviiR2Ly8/Nzenzs2LF6lx0xYgS9evVyPN64caPj/2+55RbXB+djFEWhY8eOLikiuLJrrYZ0rwlPyMvLw2b0O/eCXsxm9HP6nnMnV+YVIcQfdDodit27TvwVmx2druVH/feVvLLnwF5Msa45RqqPoii069+R4i2FLbqdWtvVa6h0YXGtYEseV4yd1Or/5sI7+UpOEUJ4D8krQgh38ao51wCefPJJ5s+fT2Vl9d19X375JYsWLaJPnz7odDq2bNmCxWLhhhtuYMKECfTr148tW7YAsGrVKlJSUujVqxd79+51mrOsW7duXHPNNUD18HS33347r7zyClBdLBo8eDCDBg2ioKCA7du31xtfVFQU9957r+O96enppKSkMGDAAKKioigoKGD37t2OrqPrrruu3nUdPXqUHj16MGDAAA4ePEh6errjteDgYG699Vageo4xPz8/KioqAHj55ZdZvXo1AQEBrF271vF8XWbNmsW9995LVFQU3bp1IywsjKKiolpdUDVzM0yYMIGBAwc6ioI//PADHTt2pG/fvgQGBpKTk8OuXbscf5+meOCBB/jkk08c844tW7aM5ORk+vTpQ2BgIDt27CA7O5uCggL8/f3p3bs3kydP5ocffgBg//79pKam0r9/fw4ePMiBAwcc627Xrh133HFHk2PztJEjR/L5558D1XPnde/endjYWLKysjx2x82Z83YMHTqUPn36oNVqufnmm52KpQB33303//d//+f0XHx8PKNGjWrxWH2BN3at1ZC514QnmM1mVBftw56iajQeGxYSXJNXhBDOAgICUCot517QjZQqq9vmF/GFvHIg8wDBAzu2+HYi+7bn+L8OYr8oCo2h5YdqB9DoNFSVuqa4ZquyUrm/nIvuvMgl6xOiLr6QU4QQ3kXyihDCHbzualXPnj357rvvnOapOnXqFL/88guLFy92uvNbo9Ewd+5cevbs6Xju+PHjLF682Kmw1rlzZ3766SenIfeefvppLrjgAsfjiooKVqxYwfbt2+nZsye9e/euN8aZM2fy5z//2fHYarWybt06fvrpJ1avXu00nN/Z5rq68cYbKSoqYunSpU6FNY1Gw4cffkh0dDRQPQnnE0884fTedevWsWzZMnQ6HQ8++GC926hx8uRJfv31V+bOncuKFSucimPXXXcd/fr1A6rv7vjhhx8cjwEKCwtZsWIF8+bNY9OmTY73njm3WEPFxMSwYMEC2rdv73iuuLiYVatW8fPPPzu6+U43e/ZsRowY4Xicn5/PkiVLnApr0dHRzJs3r1UPV/LII484dYpZrVaOHj2Kqqr85S9/8UhMV111lVNMhw4dYu7cuXz//fdOv/8aU6dOrfU3mDZtWpP3l7ZEVVWOHTvW7IPAluhaqyHda8LdrFYrdlr3HYd2lFpd6O7iqrwihHDWsWNHrHnFXvNvS1VVbHkljmHlW3pbrT2vlJaWUlZVjr4F51urofPTE9o5ipLddY+M0hIUrYJdtWO325u9rrydJxnaf4jbCrei7fGFnCKE8C6SVxpJ9bIfIVoRr7zaPX78ePbt28fjjz9O//79CQkJQafTER0dzfDhw5k+fbpj2bi4ODZu3Mg777zDyJEjCQ8PR6fTERYWxtChQ3nttdfYunUrycnJTtvw9/dn+fLlPPLIIyQkJGAwGEhISOCBBx5gzZo1Z50bSqvV8umnn/LLL79www030KlTJ/z8/NDr9cTExDBixAgef/xxtm3bxvDhw+tdz6233sqSJUu46KKLCAoKIiAggIsuuojly5c7uuxqPProo/z73/+mR48e6PV6IiIimDJlCps2baJbt271buPNN9/kH//4B0OHDqVjx45OcY4ePZpPPvmEL7/80uk9sbGxrFu3jtmzZ3PZZZcRExODXq/HZDKRmJjI+PHjef311zly5Ei92z2XgQMHsmfPHl566SWGDRvm+LtFRkZywQUX8NhjjzkNfxkcHMwvv/zC559/ztixY2nXrh06nY6goCD69+/P008/zZ49e5wKpq1Rt27dWLlyJZdccgkBAQEEBAQwfPhwFixYwKOPPuqRmOLj41m8eDGjRo0iODj4nMv7+fk5ui6humB78803t2SIPkNRFBITE5s1dEFLda3VkLnXhLvpdDo0rfwIW4PqdIOPO7kirwghajOZTESEhGErLvd0KADYisoJDwnDaGz5YpEv5JUjR45gjPZ32/baXdCRks2FqG4cSlSja37XtGpXKdtSxISxTZsOQIiG8IWcIoTwLpJXhBDuoqhSxhdCuNitt97Kxx9/DMDF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9OhRjh49yty5c7n33nt544033BG6wz/+8Q+nImCN/fv3s3//fv7973/zwQcf1CrInW7Lli289tpr5zzRq6ysZPTo0axcudLxXFVVFZ999hmbN29my5YtmEymBsX96aef8uWXX9Z6vuZ3v3jxYubOnct3332HRtP4WvKyZcsYN24cFovF6fns7Gyys7NZv349e/bsYfTo0Y7XKioquOGGG5g7d67TeyorKykpKeHAgQP06tWL3r1717nNr776io8//hibzeZ4bt26dYwbN46lS5dy0UUXOS3f1L/dqlWruPLKKzl16pTT88ePH2f+/PnMnz+fCRMm8N1332E0Nuzg/9Zbb3UUVGsUFxdTXFxMRkYGCxYsIDExkRtvvLFB62trVFUlMzOTpKQkOQgUQriE5JXWrbFdazWke020JF/NKwcPHsQU4+/pMBrEFOvPwYMH6dmzp6dD8YiKigpWb1jJoPujPR2Kk7h+Iax+YwU33Xgzfn5+ng6n1WhOTjkvpTsrdi1t1vYNBgOVpe677/xUNiQkNOw7Of+YkWEjk1o4IiF8j68eqwghvI8U15pp9+7dTJkyhYqKCsdzERER9O7dG61Wy+bNm52GZQTw9/enS5cuhIeHExAQQH5+Plu3bqWsrAyoLsBdd911DBo0qFmxTZkyhfLychYuXOh4rmvXrnTr1g2AAQMGAPDOO+84FWcMBgMDBw6ksrKSzZs3o6oqZrOZ2267jc6dOzN06NA6tzd/fvVdeklJSaSmppKRkVHncrm5ueTm5hIfH0/nzp1Zv36947Pv3buXr7/++qxFvDMZDAa6du1KREQEQUFBFBcXs23bNgoLCwH473//y7fffst1113X4HXWeOmllxyFNa1Wy6BBgwgPD+fYsWMcPHiwzkmr//rXvzoV1hRFoWfPnsTHx3P06FF27tx51m1++OGHBAQEcMEFF3Dw4EEOHToEgM1m45lnnnEqrjX1b5ednc2kSZMcvyOA1NRUOnbsyMaNGykuLgZg3rx53Hfffbz33nvn/F1lZWU5FdYiIyMZMGAANpuNI0eOkJmZidnc8LsK65tfLyMjg7i4OHbt2lXrNa1W69i/bTYbe/furXMdBoOB1NRUAMxmc73dfX5+fqSkpADVJ/Hp6el1LhcQEEBSUvVJT2lpKQcPHqxzueDgYBISEoDqouPhw4drLWO328nOziYu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CxYs0L59++zL8fHx9rhd7eKhNi6c0+udd95xiPtqvffee/r+++9VWvrbF21/f3/dcMMNGjZsmEO7smET+/bt67B++vTpWr9+vcO6gwcPmlJ0q8rfrk+fPvb1BQUFDsXC48eP680337Qve3t7q3v37leMJzc3V9OnT1dKSop9XVhYmOLj43XbbbfZ1+Xn5yszM9PZ06xTLBaLGjZsyNAFAExDXql9zOy1VobeazCTp+aVa5tfq6LM2lEQKczMV2zza10dhkuUlJTIy+re157FamEo/EowI6f4+vpq7KNPa+NSQ0WFV/dDzuCgYJUWWVVUZO4PQYsLDW1aalHvP4bK6nPlczyWUqistDD16N7L1DiAusRT71WqhSHJZrjXiw6HqEUorlXRpEmTHIpNCxcuVIsWLdS9e3f17t1bjRs31qOPPipJ6ty5s71dfn6+rr/+evXv319t27bVlClTXJL0rVarnn/+eftyYWGhunbtqvj4eN16660aOXKkfZuXl5cmTZpU4zFeyoWfpyR16dJF/fr1080336y//OUvpnyey5Yt05133qnw8HDddtttGjhwoHr16qUOHTo4tGvZsqUklSu8nT17VgkJCWrfvr3uvvtudezYUa1bt9bWrVurHFtV/nZ//etfFRISYl9+5ZVXdP3116tnz56Ki4vTsWPH7NseeughtWjR4orxFBQUaMKECWrZsqViY2PVs2dP3XPPPbr11lv1j3/8w96uQYMGpvUq9DSGYSgjI4OhCwCYhrxSu5jda60MvddgJk/NK7ExsbL9WjsKIsbJEsVeG3vlhh7IarXKVo1D95nBKDFktVpdHUatYVZOad26tW6/9S79+OXVFcktXhaFhUXofI6503T89KWhVjcGqum1V54nsLjIprVLLBo7ZoLb/KgZqI089V4FgPuhuFZF7dq105IlS1S/fn37uuzsbH333Xf65ptvlJWVZV8/duxYNW3a1L588uRJffnll9q3b5/+/Oc/Oz30ntnGjRunxx9/3L5cWFio9evX66effrL/j8jHx0dvv/22unXr5pIYKzJs2DDdeOON9uWzZ8/qq6++0q5du9SrVy917drVtGPl5ORo06ZN+uyzz/Ttt986zLHWrVs3DRgwwL48b9489e/f375sGIZ2796tL774Qjt27DB1SMSr/dtFRUVpxYoVDvOi7dmzR6tXr9aZ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y7WZO3euQ5sZM2aUa5Obm+vQ5r333ivX5nLi4+Md2j744IMO23v06OGw3cfHx9i6dWuF+zp9+rRzH8j/Wrx4scO+R48efcm2eXl5RnFxcaViT01NLfdZ3HzzzYbNZrO3ef3118u1GThwoMN+xo8fX+66vdjF19rkyZMdtq9du7bccVJTU537oP7X1V5HTz755CX36UxclY194sSJDm379u3rsL1Dhw4O2z/88MNKfQ4AAABAbUbPNQAAAADldOnSRT/++KN69eoli8Vy2bZZWVl64IEHtGzZMof169atc1j++eef5e3tLYvFYn9ZrVYdPnzYod369esve7xevXqpYcOG9uWYmJhybYYMGSI/Pz/7cqtWrcq1qaiHXEpKiiZOnKhu3bqpcePGCggIsMfaqVOncu2PHTt22ViDgoI0YsQIh3Vt2rRxKhaz2Gy2cp/poEGDKjwfSZXuudahQweHa2TevHnq1auXJkyYoHfffVebN2+2DwsaEBAgq7XqU3/ff//9Dses6BoYPny4w/LF10B1fuZmX0c+Pj5VGsr0aowZM8bhb7Vq1SodPXpUknTw4EHt2LHDvq1+/foaNGhQjcYHAAAAuBLFNQAAAAAViouL06pVq3To0CG99dZbGjZsmFq2bHnJ9pMnT3ZYPn78+FUdNz09/bLbLx56rl69euXaXFxsCQgIKNembKi9MvPmzVObNm00bdo0bdy4URkZGSooKLhsLLm5uZfdHh0d7VDkczYWM2VnZ6uwsNBhXceOHU3bf8uWLR3m6LLZbPr22281ffp0jRo1Sl27dlWDBg3Uo0cPrVmzxpRjmnENXDyHmFmq4zqKiopSWFiYmWFeUdOmTXXvvffal202m31+uIuHhBw6dGiF1zUAAADgqSiuAQAAALis6OhojR49Wh9++KEOHDig9PR0vfbaa+UepicnJ+vs2bNVPl5+fv5lt1/cs8rLq/zXmsr2vvrll1/06KOPVrrIZRjGZbdXVBDx9vau1DFqg9mzZ2v58uXq27dvhfOqFRcXa82aNerZs2e5Ho5XozquATNU13XUpEmTqoR11caNG+ew/O6778pms2nx4sUO60eNGlWTYQEAAAAuV/XxOAAAAADUKZGRkRo/frwyMjI0ffp0h23nz59XSEiIpN8KAnv27LFv69Gjh+bNm3fF/V/c06smLFmyxKEnk5eXl55++mkNGDBA4eHh8vb2VkpKirp3717jsVVVWFiY/Pz8HHqvbd++3fTjDBw4UAMHDpTNZtPhw4eVkpKiPXv2aMGCBfbjGYahqVOnavDgwaYf3x1U13XkqoLs7373O3Xq1Enbtm2TJB09elSzZs3S7t277W1uvPFGU3tCAgAAALUBPdcAAAAAOMjMzNSQIUO0devWy7Y7f/68w7K3t7dDT62EhASH7T/88IOKi4sVHR1d4SsqKkrbt293SXHt4iEsb7jhBk2bNk233nqrYmNjFR0drZ07d9ZYPL6+vuXWXalH36V4eXnp9ttvd1j36aefXvJ8cnJyKrX/vLw8nTlzxuF4MTEx6t69u8aOHat33nnHof2FBVdP427X0YWu9pp67LHHHJYvnvuNXmsAAACoi+i5BgAAAMBBaWmpPvnkE33yySdq06aN7r77bnXp0kUxMTEKDAxUZmamPvvsM7355psO7+vatavDA/yRI0dq2rRp9gf4ubm5SkhI0JNPPqnf//73Cg0N1ZkzZ7R3715t2LBBn3/+uTIyMpSamqrQ0NAaPeeIiAiH5V9++UWzZs1Sz549lZubqxUrVuiVV15xWTySNH36dP3xj3+Uv7+/JKlZs2ayWp37Sjd27FitXr3avlxcXKzExERNmDBBPXv2VEhIiI4fP65vv/1WixYtUkpKitOxHjp0SLfccot69+6tO+64Q3FxcYqMjJTVatWxY8f08ssvO7SvaNhIT+Fu19HlYpOkWbNmady4cQoMDJT0W6/UsuurzH333ae//e1vysjIkPTbtVPGz89P999/fzVGDQAAALgnimsAAAAALmnv3r3au3fvFdtZLBZNnDjRYV3Tpk01c+ZMjRkzxr7uxIkT+utf/2p6nFV1zz33aNq0afblkpISPf744w5tGjdurPT09BqJp2PHjvLx8XEoZLz44ot68cUX7cupqamKjo52an933XWXhg8frn//+9/2dWfOnNEzzzyjZ555xqFt/fr1Kx1vfn6+li9fruXLl1+xbf/+/Su9/9rC3a6jC8XGxioiIkKZmZn2dfPmzXMYqnXt2rXlepz6+vrqkUcecbj2ygwYMKDGC+EAAACAO2BYSAAAAAAOfHx8KtW7yN/fX3PnzlXPnj3LbRs9erTmz59v7xlzJeHh4QoICHD62Gbp1KmTnn766Utub968uRYuXFhj8YSGhjoUJc0wf/58Pfnkk/Lyct3XwPbt22vGjBkuO351c7fr6EJeXl7lCqnOGj16dIXDSjIkJAAAAOoqeq4BAAAAcBAWFqbs7GytW7dOGzZs0Pbt25WSkqL09HSdP39eVqtVDRo0UOvWrXXHHXdo5MiRat68+SX399BDD+nuu+/W/PnztXr1aiUnJ+v06dMyDEOhoaG67rrr1LlzZ/Xo0UN33nmnfHx8avBs/89LL72kTp066Y033tDOnTtVXFysqKgoDRw4UM8884zDvGI14bXXXlPLli31wQcfaM+ePcrNza3S/qxWq2bMmKFHHnlE77zzjtavX6/9+/fr7NmzCgwMVGRkpDp16qQ+ffpUar9t2rTRhg0btGnTJm3evFmHDh3SyZMnderUKfn4+Khhw4Zq3769Bg4cqPvvv99lf9+a4m7X0YUef/xxNWzYUG+//bZ2796ts2fPyjCMK74vMjJS9913nz788EP7uubNm6t79+7VGS4AAADgtiyGM3fSAAAAAACgzpoyZYomTZpkX540aVKFQ0UCAAAAdQHFNQAAAAAAcEn79u1TfHy8fv31V0m/9YJMTU1Vs2bNXBwZAAAA4BoMCwkAAAAAABz8+OOPGjZsmPLz85Wenu4wfORDDz1EYQ0AAAB1GsU1AAAAAADgID8/XykpKeXWt23bVi+//LILIgIAAADch5erAwAAAAAAAO7L399fbdu21cSJE7V582bVr1/f1SEBAAAALsWcawAAAAAAAAAAAICT6LkGAAAAAAAAAAAAOIniGgAAAAAAAAAAAOAkimsAAAAAAAAAAACAkyiuAQAAAAAAAAAAAE6iuAYAAAAAAAAAAAA4ieIaAAAAAAAAAAAA4CSKawAAAAAAAAAAAICTKK4BAAAAAAAAAAAATqK4BgAAAAAAAAAAADiJ4hoAAAAAAAAAAADgJIprAAAAAAAAAAAAgJMorgEAAAAAAAAAAABOorgGAAAAAAAAAAAAOOn/B793+KAE/U5dAAAAAElFTkSuQmCC\",\n \"text/plain\": [\n \"\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n }\n ],\n \"source\": [\n \"# 5.4 Semantic Alignment Visualization (Column-Level RBAC)\\n\",\n \"# Circle size = column coverage, Red triangles = SystemManager\\n\",\n \"import random\\n\",\n \"import math\\n\",\n \"import matplotlib.pyplot as plt\\n\",\n \"from matplotlib.colors import PowerNorm\\n\",\n \"from matplotlib import colormaps as cm\\n\",\n \"from collections import defaultdict\\n\",\n \"from matplotlib.lines import Line2D\\n\",\n \"import numpy as np\\n\",\n \"\\n\",\n \"sys.path.insert(0, str(project_root / \\\"plot\\\"))\\n\",\n \"from embedding_utils import cosine_similarity\\n\",\n \"\\n\",\n \"# Prepare records (recompute)\\n\",\n \"role_records = evaluator._prepare_role_records()\\n\",\n \"evaluator._compute_embeddings()\\n\",\n \"\\n\",\n \"# Build vis_records with is_system_manager\\n\",\n \"vis_records = []\\n\",\n \"for spec in role_records:\\n\",\n \" schema_emb = evaluator._schema_emb_dict.get(spec[\\\"schema_text\\\"])\\n\",\n \" role_emb = evaluator._role_emb_dict.get(spec[\\\"role_text\\\"])\\n\",\n \" \\n\",\n \" if schema_emb is not None and role_emb is not None:\\n\",\n \" raw_sim = cosine_similarity(role_emb, schema_emb)\\n\",\n \" similarity = max(0.0, min(1.0, (raw_sim + 1.0) / 2.0))\\n\",\n \" else:\\n\",\n \" similarity = 0.5\\n\",\n \" \\n\",\n \" total_cols = spec.get(\\\"total_columns\\\", 1)\\n\",\n \" accessible_cols = spec.get(\\\"accessible_columns\\\", 0)\\n\",\n \" col_coverage = accessible_cols / total_cols if total_cols > 0 else 0\\n\",\n \" \\n\",\n \" vis_records.append({\\n\",\n \" \\\"db_id\\\": spec[\\\"db_id\\\"],\\n\",\n \" \\\"role\\\": spec[\\\"role\\\"],\\n\",\n \" \\\"similarity\\\": similarity,\\n\",\n \" \\\"is_system_manager\\\": spec.get(\\\"is_system_manager\\\", False),\\n\",\n \" \\\"column_coverage\\\": col_coverage,\\n\",\n \" })\\n\",\n \"\\n\",\n \"sm_count = sum(1 for r in vis_records if r[\\\"is_system_manager\\\"])\\n\",\n \"print(f\\\"Total roles: {len(vis_records)}, SystemManager: {sm_count}\\\")\\n\",\n \"\\n\",\n \"# Plot function\\n\",\n \"def plot_semantic(records, output_path, title, dbs_per_panel=12):\\n\",\n \" db_to_entries = defaultdict(list)\\n\",\n \" sims = []\\n\",\n \" for rec in records:\\n\",\n \" sims.append(rec[\\\"similarity\\\"])\\n\",\n \" size = 90.0 + rec[\\\"column_coverage\\\"] * 220.0\\n\",\n \" db_to_entries[rec[\\\"db_id\\\"]].append({\\n\",\n \" \\\"sim\\\": rec[\\\"similarity\\\"], \\\"size\\\": size,\\n\",\n \" \\\"is_sm\\\": rec[\\\"is_system_manager\\\"],\\n\",\n \" })\\n\",\n \" \\n\",\n \" db_ids = sorted(db_to_entries.keys())\\n\",\n \" panels = [db_ids[i:i+dbs_per_panel] for i in range(0, len(db_ids), dbs_per_panel)]\\n\",\n \" \\n\",\n \" min_s, max_s = min(sims), max(sims)\\n\",\n \" if math.isclose(min_s, max_s): max_s = min_s + 1e-6\\n\",\n \" span = max_s - min_s\\n\",\n \" norm = PowerNorm(gamma=0.55, vmin=min_s, vmax=max_s)\\n\",\n \" cmap = cm[\\\"viridis\\\"]\\n\",\n \" \\n\",\n \" fig = plt.figure(figsize=(11, sum(0.35*len(p)+0.6 for p in panels)+2))\\n\",\n \" gs = fig.add_gridspec(len(panels), 1, height_ratios=[0.35*len(p)+0.6 for p in panels], hspace=0.18)\\n\",\n \" axes = []\\n\",\n \" \\n\",\n \" random.seed(42)\\n\",\n \" sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)\\n\",\n \" sm.set_array([])\\n\",\n \" \\n\",\n \" for pi, chunk in enumerate(panels):\\n\",\n \" ax = fig.add_subplot(gs[pi, 0])\\n\",\n \" axes.append(ax)\\n\",\n \" for ri, db in enumerate(chunk):\\n\",\n \" y = float(ri)\\n\",\n \" ax.axhline(y, color=\\\"#d0d0d0\\\", linestyle=\\\"--\\\", lw=0.9, zorder=0)\\n\",\n \" for e in db_to_entries[db]:\\n\",\n \" x = (e[\\\"sim\\\"] - min_s) / span + random.uniform(-0.012, 0.012)\\n\",\n \" if e[\\\"is_sm\\\"]:\\n\",\n \" ax.scatter(x, y, s=250, c=\\\"#d62728\\\", alpha=0.95,\\n\",\n \" edgecolors=\\\"#8c1c15\\\", lw=1.0, marker=\\\"^\\\", zorder=4)\\n\",\n \" else:\\n\",\n \" ax.scatter(x, y + random.uniform(-0.16, 0.16), s=e[\\\"size\\\"]*2.5,\\n\",\n \" c=[e[\\\"sim\\\"]], cmap=cmap, norm=norm, alpha=0.82,\\n\",\n \" edgecolors=\\\"#333\\\", lw=0.45, marker=\\\"o\\\")\\n\",\n \" ax.set_yticks(range(len(chunk)))\\n\",\n \" ax.set_yticklabels(chunk, fontsize=10, weight='bold')\\n\",\n \" ax.set_xlim(-0.05, 1.05)\\n\",\n \" ax.set_ylim(-0.6, len(chunk)-0.4)\\n\",\n \" ax.set_xticks(np.linspace(0, 1, 5))\\n\",\n \" ax.set_xticklabels([f\\\"{min_s + p*span:.2f}\\\" for p in np.linspace(0,1,5)], fontsize=9)\\n\",\n \" ax.grid(axis=\\\"x\\\", ls=\\\":\\\", lw=0.5, alpha=0.45)\\n\",\n \" \\n\",\n \" axes[-1].set_xlabel(\\\"Semantic similarity\\\", fontsize=12, weight='bold')\\n\",\n \" fig.suptitle(f\\\"{title}: Role-Schema Alignment\\\", fontsize=14, y=0.98, weight='bold')\\n\",\n \" cbar = fig.colorbar(sm, ax=axes, fraction=0.03, pad=0.015)\\n\",\n \" cbar.set_label(\\\"Similarity\\\", fontsize=10)\\n\",\n \" \\n\",\n \" legend = [\\n\",\n \" Line2D([0],[0], marker='^', color='w', markerfacecolor='#d62728',\\n\",\n \" markeredgecolor='#8c1c15', markersize=12, label='SystemManager'),\\n\",\n \" Line2D([0],[0], marker='o', color='w', markerfacecolor='#21918c',\\n\",\n \" markeredgecolor='#333', markersize=8, label='Other (size=col coverage)'),\\n\",\n \" ]\\n\",\n \" fig.legend(handles=legend, loc='upper right', fontsize=9)\\n\",\n \" plt.tight_layout(rect=[0,0,0.95,0.95])\\n\",\n \" fig.savefig(output_path, dpi=150, bbox_inches='tight')\\n\",\n \" plt.close(fig)\\n\",\n \" print(f\\\"Saved: {output_path}\\\")\\n\",\n \"\\n\",\n \"output_path = project_root / \\\"plot\\\" / \\\"column_level_rbac_semantic.png\\\"\\n\",\n \"plot_semantic(vis_records, output_path, \\\"Column-Level RBAC (BIRD)\\\")\\n\",\n \"from IPython.display import Image, display\\n\",\n \"display(Image(filename=str(output_path)))\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 13,\n \"id\": \"2dd807b4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Databases Requiring Review (1/11) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseDeny%AllAllow%CoverageCovStdMaxOverlapIssues
0california_schools63.1%5.6%50.8%0.05972.3%all-deny queries found (1) - SystemManager coverage broken; Low role diversity
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Deny% AllAllow% Coverage CovStd MaxOverlap \\\\\\n\",\n \"0 california_schools 63.1% 5.6% 50.8% 0.059 72.3% \\n\",\n \"\\n\",\n \" Issues \\n\",\n \"0 all-deny queries found (1) - SystemManager coverage broken; Low role diversity \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"Issue Thresholds:\\n\",\n \" - Deny% < 5%: roles too permissive\\n\",\n \" - Coverage > 85%: most roles have near-full access\\n\",\n \" - CovStd < 0.065: roles have similar coverage (low diversity)\\n\",\n \" - MaxOverlap >80%: redundant roles with similar policies\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 5.5 Export Problematic Databases as DataFrame\\n\",\n \"if report.databases_with_issues:\\n\",\n \" issues_data = []\\n\",\n \" for db_id in report.databases_with_issues:\\n\",\n \" row = {\\\"Database\\\": db_id}\\n\",\n \" \\n\",\n \" if db_id in report.deny_rate_metrics:\\n\",\n \" m = report.deny_rate_metrics[db_id]\\n\",\n \" row[\\\"Deny%\\\"] = f\\\"{m.deny_rate:.1f}%\\\"\\n\",\n \" row[\\\"AllAllow%\\\"] = f\\\"{m.all_allow_pct:.1f}%\\\"\\n\",\n \" \\n\",\n \" if db_id in report.semantic_metrics:\\n\",\n \" m = report.semantic_metrics[db_id]\\n\",\n \" row[\\\"Coverage\\\"] = f\\\"{m.avg_coverage:.1%}\\\" # Source of \\\"Most roles too permissive\\\" (>90%)\\n\",\n \" row[\\\"CovStd\\\"] = f\\\"{m.coverage_std:.3f}\\\" # Source of \\\"Low role diversity\\\" (<0.1)\\n\",\n \" \\n\",\n \" if db_id in report.overlap_metrics:\\n\",\n \" m = report.overlap_metrics[db_id]\\n\",\n \" row[\\\"MaxOverlap\\\"] = f\\\"{m.max_overlap:.1%}\\\" # Source of \\\"High max overlap\\\" (>70%)\\n\",\n \" \\n\",\n \" row[\\\"Issues\\\"] = \\\"; \\\".join(report.all_issues.get(db_id, []))\\n\",\n \" issues_data.append(row)\\n\",\n \" \\n\",\n \" issues_df = pd.DataFrame(issues_data)\\n\",\n \" print(f\\\"=== Databases Requiring Review ({len(issues_df)}/{report.total_databases}) ===\\\")\\n\",\n \" \\n\",\n \" # Display with full column width for Issues column\\n\",\n \" pd.set_option('display.max_colwidth', None)\\n\",\n \" pd.set_option('display.max_rows', None)\\n\",\n \" display(issues_df)\\n\",\n \" pd.reset_option('display.max_colwidth')\\n\",\n \" pd.reset_option('display.max_rows')\\n\",\n \" \\n\",\n \" print(\\\"\\\\nIssue Thresholds:\\\")\\n\",\n \" print(\\\" - Deny% < 5%: roles too permissive\\\")\\n\",\n \" print(\\\" - Coverage > 85%: most roles have near-full access\\\")\\n\",\n \" print(\\\" - CovStd < 0.065: roles have similar coverage (low diversity)\\\")\\n\",\n \" print(\\\" - MaxOverlap >80%: redundant roles with similar policies\\\")\\n\",\n \"\\n\",\n \"else:\\n\",\n \" print(\\\"[OK] All databases pass quality checks!\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"7586c455\",\n \"metadata\": {},\n \"source\": [\n \"## 6. Regenerate Roles for Problematic Databases\\n\",\n \"\\n\",\n \"Human-in-the-loop workflow for fixing quality issues:\\n\",\n \"\\n\",\n \"| Step | Cell | Description |\\n\",\n \"|------|------|-------------|\\n\",\n \"| 1 | 6.1 | Select database, view schema and current roles |\\n\",\n \"| 2 | 6.2 | Write regeneration hints (edit manually) |\\n\",\n \"| 3 | 6.3 | Execute regeneration with LLM |\\n\",\n \"| 4 | 6.4 | Preview and compare OLD vs NEW |\\n\",\n \"| 5 | 6.4.1 | Select & combine roles from OLD and NEW |\\n\",\n \"| 6 | 6.5 | Apply changes if satisfied |\\n\",\n \"| 7 | 6.6 | Regenerate RBAC Dataset with updated roles |\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 32,\n \"id\": \"70f25858\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"Database: formula_1\\n\",\n \"======================================================================\\n\",\n \"\\n\",\n \"=== Schema (13 tables, 94 columns) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
TableColumnTypePKFK
0circuitscircuitIdINTEGERYes
1circuitscircuitRefTEXT
2circuitsnameTEXT
3circuitslocationTEXT
4circuitscountryTEXT
..................
89resultsfastestLapINTEGER
90resultsrankINTEGER
91resultsfastestLapTimeTEXT
92resultsfastestLapSpeedTEXT
93resultsstatusIdINTEGERstatus.statusId
\\n\",\n \"

94 rows × 5 columns

\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Table Column Type PK FK\\n\",\n \"0 circuits circuitId INTEGER Yes \\n\",\n \"1 circuits circuitRef TEXT \\n\",\n \"2 circuits name TEXT \\n\",\n \"3 circuits location TEXT \\n\",\n \"4 circuits country TEXT \\n\",\n \".. ... ... ... ... ...\\n\",\n \"89 results fastestLap INTEGER \\n\",\n \"90 results rank INTEGER \\n\",\n \"91 results fastestLapTime TEXT \\n\",\n \"92 results fastestLapSpeed TEXT \\n\",\n \"93 results statusId INTEGER status.statusId\\n\",\n \"\\n\",\n \"[94 rows x 5 columns]\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Current Roles (5) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
RoleDescriptionTablesColumnsPolicy
0RaceAnalystAnalyzes race performance data including lap times, pit stops, and qualifying results965 (*)circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date, time]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]; status: [statusId, status]
1StandingsManagerManages championship standings and constructor/driver points calculations743 (*)constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; results: [resultId, raceId, driverId, constructorId, position, positionOrder, points]
2MediaCoordinatorProvides public information for media and fan engagement633 (*)circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, constructorRef, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [*]; races: [raceId, year, round, circuitId, name, date, time, url]; status: [statusId, status]
3DriverManagerManages driver information and personal details including date of birth432 (*)drivers: [*]; races: [raceId, year, round, name, date]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, statusId]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]
4SystemManagerFull administrative access for system maintenance and data integrity1394 (*)circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*]
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Role \\\\\\n\",\n \"0 RaceAnalyst \\n\",\n \"1 StandingsManager \\n\",\n \"2 MediaCoordinator \\n\",\n \"3 DriverManager \\n\",\n \"4 SystemManager \\n\",\n \"\\n\",\n \" Description \\\\\\n\",\n \"0 Analyzes race performance data including lap times, pit stops, and qualifying results \\n\",\n \"1 Manages championship standings and constructor/driver points calculations \\n\",\n \"2 Provides public information for media and fan engagement \\n\",\n \"3 Manages driver information and personal details including date of birth \\n\",\n \"4 Full administrative access for system maintenance and data integrity \\n\",\n \"\\n\",\n \" Tables Columns \\\\\\n\",\n \"0 9 65 (*) \\n\",\n \"1 7 43 (*) \\n\",\n \"2 6 33 (*) \\n\",\n \"3 4 32 (*) \\n\",\n \"4 13 94 (*) \\n\",\n \"\\n\",\n \" Policy \\n\",\n \"0 circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date, time]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]; status: [statusId, status] \\n\",\n \"1 constructors: [constructorId, constructorRef, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; results: [resultId, raceId, driverId, constructorId, position, positionOrder, points] \\n\",\n \"2 circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, constructorRef, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [*]; races: [raceId, year, round, circuitId, name, date, time, url]; status: [statusId, status] \\n\",\n \"3 drivers: [*]; races: [raceId, year, round, name, date]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, statusId]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins] \\n\",\n \"4 circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*] \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Role x Table Matrix (column counts, * expanded) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
TablecircuitsconstructorResultsconstructorStandingsconstructorsdriverStandingsdriverslapTimespitStopsqualifyingracesresultsseasonsstatus
Role             
DriverManager0.0000000.0000000.0000000.0000007.0000009.0000000.0000000.0000000.0000005.00000011.0000000.0000000.000000
MediaCoordinator8.0000000.0000000.0000005.0000000.0000008.0000000.0000000.0000000.0000008.0000000.0000002.0000002.000000
RaceAnalyst6.0000000.0000000.0000004.0000000.0000007.0000006.0000007.0000009.0000007.00000017.0000000.0000002.000000
StandingsManager0.0000005.0000007.0000004.0000007.0000007.0000000.0000000.0000000.0000006.0000007.0000000.0000000.000000
SystemManager9.0000005.0000007.0000005.0000007.0000009.0000006.0000007.0000009.0000008.00000018.0000002.0000002.000000
\\n\"\n ],\n \"text/plain\": [\n \"\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"[SUMMARY] 1 database(s) selected: ['formula_1']\\n\",\n \"[NEXT] Edit hints in Cell 6.2, then run Cell 6.3\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.1 Select Database(s) & View Current State\\n\",\n \"# Supports single db (str) or multiple dbs (list)\\n\",\n \"\\n\",\n \"TARGET_DBS = [\\\"formula_1\\\"] # Single: \\\"toxicology\\\" or Multiple: [\\\"toxicology\\\", \\\"california_schools\\\"]\\n\",\n \"\\n\",\n \"# Normalize to list\\n\",\n \"if isinstance(TARGET_DBS, str):\\n\",\n \" TARGET_DBS = [TARGET_DBS]\\n\",\n \"\\n\",\n \"# Load current role assignments\\n\",\n \"with open(ROLE_ASSIGNMENTS_PATH, 'r') as f:\\n\",\n \" all_assignments = json.load(f)\\n\",\n \"\\n\",\n \"available_dbs = set(all_assignments.get('assignments', {}).keys())\\n\",\n \"valid_target_dbs = [db for db in TARGET_DBS if db in available_dbs]\\n\",\n \"invalid_dbs = [db for db in TARGET_DBS if db not in available_dbs]\\n\",\n \"\\n\",\n \"if invalid_dbs:\\n\",\n \" print(f\\\"[WARN] Databases not found: {invalid_dbs}\\\")\\n\",\n \" print(f\\\"Available: {sorted(available_dbs)}\\\\n\\\")\\n\",\n \"\\n\",\n \"# Store schemas for later use\\n\",\n \"target_schemas = {}\\n\",\n \"\\n\",\n \"for TARGET_DB in valid_target_dbs:\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"Database: {TARGET_DB}\\\")\\n\",\n \" print(f\\\"{'='*70}\\\")\\n\",\n \" \\n\",\n \" # --- Schema Summary ---\\n\",\n \" db_path = bird_db_dir / TARGET_DB / f\\\"{TARGET_DB}.sqlite\\\"\\n\",\n \" if db_path.exists():\\n\",\n \" target_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" target_schemas[TARGET_DB] = target_schema\\n\",\n \" \\n\",\n \" schema_rows = []\\n\",\n \" for table, info in target_schema.items():\\n\",\n \" for col in info['columns']:\\n\",\n \" schema_rows.append({\\n\",\n \" \\\"Table\\\": table,\\n\",\n \" \\\"Column\\\": col['name'],\\n\",\n \" \\\"Type\\\": col['type'],\\n\",\n \" \\\"PK\\\": \\\"Yes\\\" if col['pk'] else \\\"\\\",\\n\",\n \" \\\"FK\\\": col.get('fk', '') or \\\"\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" schema_df = pd.DataFrame(schema_rows)\\n\",\n \" print(f\\\"\\\\n=== Schema ({len(target_schema)} tables, {len(schema_df)} columns) ===\\\")\\n\",\n \" display(schema_df)\\n\",\n \" else:\\n\",\n \" print(f\\\"[ERROR] Database not found: {db_path}\\\")\\n\",\n \" target_schemas[TARGET_DB] = None\\n\",\n \" continue\\n\",\n \"\\n\",\n \" # --- Current Roles ---\\n\",\n \" if TARGET_DB in all_assignments.get('assignments', {}):\\n\",\n \" current_roles = all_assignments['assignments'][TARGET_DB]\\n\",\n \" \\n\",\n \" # Set display options for full content\\n\",\n \" pd.set_option('display.max_colwidth', None)\\n\",\n \" \\n\",\n \" roles_rows = []\\n\",\n \" for role_info in current_roles:\\n\",\n \" policy = role_info.get('policy', {})\\n\",\n \" total_access = count_policy_columns(policy, target_schema)\\n\",\n \" has_wildcard = has_wildcard_policy(policy)\\n\",\n \" cols_display = f\\\"{total_access}\\\" + (\\\" (*)\\\" if has_wildcard else \\\"\\\")\\n\",\n \" # Full policy string\\n\",\n \" policy_str = \\\"; \\\".join([\\n\",\n \" f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" \\n\",\n \" for t, c in policy.items()\\n\",\n \" ])\\n\",\n \" roles_rows.append({\\n\",\n \" \\\"Role\\\": role_info['role'],\\n\",\n \" \\\"Description\\\": role_info.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Columns\\\": cols_display,\\n\",\n \" \\\"Policy\\\": policy_str\\n\",\n \" })\\n\",\n \" \\n\",\n \" roles_df = pd.DataFrame(roles_rows)\\n\",\n \" print(f\\\"\\\\n=== Current Roles ({len(current_roles)}) ===\\\")\\n\",\n \" display(roles_df)\\n\",\n \" \\n\",\n \" pd.reset_option('display.max_colwidth')\\n\",\n \" \\n\",\n \" # Policy detail matrix\\n\",\n \" policy_rows = []\\n\",\n \" for role_info in current_roles:\\n\",\n \" policy = role_info.get('policy', {})\\n\",\n \" for table, cols in policy.items():\\n\",\n \" num_cols = count_policy_columns({table: cols}, target_schema)\\n\",\n \" policy_rows.append({\\n\",\n \" \\\"Role\\\": role_info['role'],\\n\",\n \" \\\"Table\\\": table,\\n\",\n \" \\\"NumCols\\\": num_cols\\n\",\n \" })\\n\",\n \" \\n\",\n \" if policy_rows:\\n\",\n \" policy_df = pd.DataFrame(policy_rows)\\n\",\n \" pivot = policy_df.pivot_table(index='Role', columns='Table', values='NumCols', fill_value=0)\\n\",\n \" print(\\\"\\\\n=== Role x Table Matrix (column counts, * expanded) ===\\\")\\n\",\n \" display(pivot.style.background_gradient(cmap='Blues', axis=None))\\n\",\n \" \\n\",\n \" # Quality issues\\n\",\n \" if 'report' in dir() and TARGET_DB in report.all_issues:\\n\",\n \" print(f\\\"\\\\n=== Quality Issues ===\\\")\\n\",\n \" issues = report.all_issues[TARGET_DB]\\n\",\n \" if TARGET_DB in report.deny_rate_metrics:\\n\",\n \" m = report.deny_rate_metrics[TARGET_DB]\\n\",\n \" issues_df = pd.DataFrame([{\\n\",\n \" \\\"Deny Rate\\\": f\\\"{m.deny_rate:.1f}%\\\",\\n\",\n \" \\\"All-Allow %\\\": f\\\"{m.all_allow_pct:.1f}%\\\",\\n\",\n \" \\\"Issues\\\": \\\"; \\\".join(issues)\\n\",\n \" }])\\n\",\n \" display(issues_df)\\n\",\n \" else:\\n\",\n \" print(f\\\"[ERROR] No roles found for {TARGET_DB}\\\")\\n\",\n \"\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"[SUMMARY] {len(valid_target_dbs)} database(s) selected: {valid_target_dbs}\\\")\\n\",\n \" print(\\\"[NEXT] Edit hints in Cell 6.2, then run Cell 6.3\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[INFO] No databases selected. Edit TARGET_DBS above and re-run.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 34,\n \"id\": \"f8416bc4\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Applying shared hint to 1 database(s) ===\\n\",\n \"\\n\",\n \" ✓ formula_1: 13 tables, 94 columns\\n\",\n \"\\n\",\n \"[NEXT] Run Cell 6.3 to regenerate all 1 database(s)\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.2 Write Regeneration Hints (Human-in-the-Loop)\\n\",\n \"# Write ONE shared hint for all selected databases (they have similar issues)\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EDIT HERE: Shared problem description for all selected DBs\\n\",\n \"# Supports {db}, {num_tables}, {num_cols} placeholders\\n\",\n \"# ============================================================\\n\",\n \"# PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"# [PROBLEM]\\n\",\n \"# Low deny rate - almost all queries are allowed by all roles (roles too permissive)\\n\",\n \"# Low diversity - all roles have similar access patterns (coverage_std too low)\\n\",\n \"\\n\",\n \"\\n\",\n \"# [ROOT CAUSE]\\n\",\n \"# - Most roles can access most/all columns, so very few queries get denied\\n\",\n \"# - This defeats the purpose of RBAC - no meaningful access control\\n\",\n \"\\n\",\n \"# [DIRECTION]\\n\",\n \"# - Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"# - Create restrictive roles that only access specific subsets of data\\n\",\n \"# - Each role should have a clear, limited scope\\n\",\n \"# - Some roles should be restricted to fewer tables\\n\",\n \"# - Do not frequently giving non-admin roles \\\"*\\\" (all columns) access\\n\",\n \"# - Create clear functional boundaries between roles\\n\",\n \"# \\\"\\\"\\\"\\n\",\n \"\\n\",\n \"# All-denied cases - even SystemManager role cannot access some columns\\n\",\n \"# - Ensure SystemManager role has full access to all tables and columns\\n\",\n \"\\n\",\n \"\\n\",\n \"PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"[PROBLEM]\\n\",\n \"Low semantic alignment - roles do not align well with schema\\n\",\n \"All-denied cases - even SystemManager role cannot access some columns\\n\",\n \"\\n\",\n \"[ROOT CAUSE]\\n\",\n \"- This defeats the purpose of RBAC - no meaningful access control\\n\",\n \"\\n\",\n \"[DIRECTION]\\n\",\n \"- Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"- Ensure SystemManager role has full access to all tables and columns\\n\",\n \"- Review other roles to ensure they align with specific functional areas\\n\",\n \"- Each role should have a clear, limited scope\\n\",\n \"- Create meaningful semantic role names and descriptions that reflect their access patterns\\n\",\n \"\\\"\\\"\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"# PROBLEM_TO_FIX = \\\"\\\"\\\"\\n\",\n \"# [PROBLEM]\\n\",\n \"# Low diversity - all roles have similar access patterns (coverage_std too low)\\n\",\n \"\\n\",\n \"# [ROOT CAUSE]\\n\",\n \"# - This defeats the purpose of RBAC - no meaningful access control differentiation\\n\",\n \"\\n\",\n \"# [DIRECTION]\\n\",\n \"# - Database: {db} ({num_tables} tables, {num_cols} columns)\\n\",\n \"# - Create restrictive roles that only access specific subsets of data\\n\",\n \"# - Each role should have a clear, limited scope\\n\",\n \"# - Some roles should be restricted to fewer tables\\n\",\n \"# - Do not frequently giving non-admin roles \\\"*\\\" (all columns) access\\n\",\n \"# - Create clear functional boundaries between roles\\n\",\n \"# \\\"\\\"\\\"\\n\",\n \"\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# Auto-apply to all selected databases (no need to edit below)\\n\",\n \"# ============================================================\\n\",\n \"REGENERATION_HINTS = {}\\n\",\n \"\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"=== Applying shared hint to {len(valid_target_dbs)} database(s) ===\\\\n\\\")\\n\",\n \" for db in valid_target_dbs:\\n\",\n \" schema = target_schemas.get(db, {})\\n\",\n \" num_tables = len(schema)\\n\",\n \" num_cols = sum(len(t['columns']) for t in schema.values())\\n\",\n \" \\n\",\n \" # Fill placeholders\\n\",\n \" REGENERATION_HINTS[db] = PROBLEM_TO_FIX.format(\\n\",\n \" db=db, num_tables=num_tables, num_cols=num_cols\\n\",\n \" )\\n\",\n \" print(f\\\" ✓ {db}: {num_tables} tables, {num_cols} columns\\\")\\n\",\n \"\\n\",\n \" print(f\\\"\\\\n[NEXT] Run Cell 6.3 to regenerate all {len(valid_target_dbs)} database(s)\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[INFO] No databases selected. Run Cell 6.1 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 68,\n \"id\": \"91109a7c\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"Regenerating roles for 1 database(s)...\\n\",\n \"============================================================\\n\",\n \"\\n\",\n \"[formula_1] Generating...\\n\",\n \" ✓ 5 roles (5 valid)\\n\",\n \"\\n\",\n \"============================================================\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseStatusRolesValidTokens
0formula_1success553058
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Status Roles Valid Tokens\\n\",\n \"0 formula_1 success 5 5 3058\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"[OK] All databases regenerated. Run Cell 6.4 to preview.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.3 Execute Regeneration with Hints (supports multiple databases)\\n\",\n \"\\n\",\n \"def regenerate_single_database(db_name: str, hint: str) -> dict:\\n\",\n \" \\\"\\\"\\\"Regenerate roles for a single database with guidance hints.\\\"\\\"\\\"\\n\",\n \" db_path = bird_db_dir / db_name / f\\\"{db_name}.sqlite\\\"\\n\",\n \" \\n\",\n \" if not db_path.exists():\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": \\\"Database not found\\\"}\\n\",\n \" \\n\",\n \" try:\\n\",\n \" db_schema = get_schema_from_sqlite(str(db_path))\\n\",\n \" db_schema_text = format_schema_for_prompt(db_schema, db_name)\\n\",\n \" \\n\",\n \" enhanced_system_prompt = f\\\"{COLUMN_LEVEL_SYSTEM_PROMPT}\\\\n\\\\n[OPTIMIZATION GUIDANCE]\\\\n{hint}\\\"\\n\",\n \" user_prompt = COLUMN_LEVEL_USER_PROMPT_TEMPLATE.format(schema_content=db_schema_text)\\n\",\n \" \\n\",\n \" response = oracle.query(\\n\",\n \" prompt_sys=enhanced_system_prompt,\\n\",\n \" prompt_user=user_prompt,\\n\",\n \" temp=0.3,\\n\",\n \" top_p=0.9,\\n\",\n \" max_completion_tokens=DEFAULT_MAX_TOKENS\\n\",\n \" )\\n\",\n \" \\n\",\n \" llm_response = response['answer']\\n\",\n \" usage = response.get('usage', {})\\n\",\n \" roles = parse_column_level_roles(llm_response)\\n\",\n \" \\n\",\n \" if not roles:\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"parse_error\\\", \\n\",\n \" \\\"error\\\": \\\"Failed to parse LLM response\\\", \\\"raw_response\\\": llm_response[:500]}\\n\",\n \" \\n\",\n \" validation = validate_roles_against_schema(roles, str(db_path))\\n\",\n \" assignments = [{\\\"role\\\": r[\\\"role\\\"], \\\"description\\\": r.get(\\\"description\\\", \\\"\\\"), \\n\",\n \" \\\"policy\\\": r.get(\\\"columns\\\", {})} for r in roles]\\n\",\n \" \\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"success\\\", \\\"roles_count\\\": len(assignments),\\n\",\n \" \\\"valid_roles\\\": validation['valid_roles'], \\\"all_valid\\\": validation['all_valid'],\\n\",\n \" \\\"assignments\\\": assignments, \\\"usage\\\": usage, \\\"raw_response\\\": llm_response}\\n\",\n \" except Exception as e:\\n\",\n \" return {\\\"database\\\": db_name, \\\"status\\\": \\\"error\\\", \\\"error\\\": str(e)}\\n\",\n \"\\n\",\n \"# Execute for all target databases\\n\",\n \"if valid_target_dbs:\\n\",\n \" print(f\\\"Regenerating roles for {len(valid_target_dbs)} database(s)...\\\")\\n\",\n \" print(\\\"=\\\"*60)\\n\",\n \"\\n\",\n \" regenerated_results = {} # Store all results\\n\",\n \" all_success = True\\n\",\n \"\\n\",\n \" for db_name in valid_target_dbs:\\n\",\n \" hint = REGENERATION_HINTS.get(db_name, PROBLEM_TO_FIX)\\n\",\n \" print(f\\\"\\\\n[{db_name}] Generating...\\\")\\n\",\n \" \\n\",\n \" result = regenerate_single_database(db_name, hint)\\n\",\n \" regenerated_results[db_name] = result\\n\",\n \" \\n\",\n \" if result[\\\"status\\\"] == \\\"success\\\":\\n\",\n \" print(f\\\" ✓ {result['roles_count']} roles ({result['valid_roles']} valid)\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" ✗ {result.get('error', result['status'])}\\\")\\n\",\n \" all_success = False\\n\",\n \"\\n\",\n \" # Summary table\\n\",\n \" print(\\\"\\\\n\\\" + \\\"=\\\"*60)\\n\",\n \" result_df = pd.DataFrame([{\\n\",\n \" \\\"Database\\\": r[\\\"database\\\"],\\n\",\n \" \\\"Status\\\": r[\\\"status\\\"],\\n\",\n \" \\\"Roles\\\": r.get(\\\"roles_count\\\", \\\"N/A\\\"),\\n\",\n \" \\\"Valid\\\": r.get(\\\"valid_roles\\\", \\\"N/A\\\"),\\n\",\n \" \\\"Tokens\\\": r.get(\\\"usage\\\", {}).get(\\\"total_tokens\\\", \\\"N/A\\\")\\n\",\n \" } for r in regenerated_results.values()])\\n\",\n \" display(result_df)\\n\",\n \"\\n\",\n \" if all_success:\\n\",\n \" print(\\\"\\\\n[OK] All databases regenerated. Run Cell 6.4 to preview.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"\\\\n[WARN] Some databases failed. Check errors above.\\\")\\n\",\n \"else:\\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"[INFO] No databases selected. Run Cell 6.1 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 69,\n \"id\": \"a2b0ba98\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"======================================================================\\n\",\n \"Database: formula_1\\n\",\n \"======================================================================\\n\",\n \"\\n\",\n \"=== NEW Roles (5) ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
RoleDescriptionTablesColsPolicy
0SystemManagerFull administrative access for system maintenance and data management1394 (*)circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*]
1RaceAnalystAnalyzes race performance data including lap times, pit stops, and qualifying results861circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; lapTimes: [raceId, driverId, lap, position, time, milliseconds]; pitStops: [raceId, driverId, stop, lap, time, duration, milliseconds]; qualifying: [qualifyId, raceId, driverId, constructorId, number, position, q1, q2, q3]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId]
2StandingsManagerManages and monitors championship standings for drivers and constructors742constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, name, date]; constructorResults: [constructorResultsId, raceId, constructorId, points, status]; constructorStandings: [constructorStandingsId, raceId, constructorId, points, position, positionText, wins]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, points, position, positionText, statusId]
3PublicRelationsAccesses public information about circuits, drivers, constructors, and race schedules631circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [year, url]; races: [raceId, year, round, circuitId, name, date, url]; status: [statusId, status]
4DriverManagerManages driver information and personal details including date of birth432drivers: [driverId, driverRef, number, code, forename, surname, dob, nationality]; races: [raceId, year, round, name, date]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionText, positionOrder, points, laps, statusId]
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Role \\\\\\n\",\n \"0 SystemManager \\n\",\n \"1 RaceAnalyst \\n\",\n \"2 StandingsManager \\n\",\n \"3 PublicRelations \\n\",\n \"4 DriverManager \\n\",\n \"\\n\",\n \" Description \\\\\\n\",\n \"0 Full administrative access for system maintenance and data management \\n\",\n \"1 Analyzes race performance data including lap times, pit stops, and qualifying results \\n\",\n \"2 Manages and monitors championship standings for drivers and constructors \\n\",\n \"3 Accesses public information about circuits, drivers, constructors, and race schedules \\n\",\n \"4 Manages driver information and personal details including date of birth \\n\",\n \"\\n\",\n \" Tables Cols \\\\\\n\",\n \"0 13 94 (*) \\n\",\n \"1 8 61 \\n\",\n \"2 7 42 \\n\",\n \"3 6 31 \\n\",\n \"4 4 32 \\n\",\n \"\\n\",\n \" Policy \\n\",\n \"0 circuits: [*]; constructors: [*]; drivers: [*]; seasons: [*]; races: [*]; constructorResults: [*]; constructorStandings: [*]; driverStandings: [*]; lapTimes: [*]; pitStops: [*]; qualifying: [*]; status: [*]; results: [*] \\n\",\n \"1 circuits: [circuitId, name, location, country, lat, lng]; constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, circuitId, name, date]; lapTimes: [raceId, driverId, lap, position, time, milliseconds]; pitStops: [raceId, driverId, stop, lap, time, duration, milliseconds]; qualifying: [qualifyId, raceId, driverId, constructorId, number, position, q1, q2, q3]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionOrder, points, laps, time, milliseconds, fastestLap, rank, fastestLapTime, fastestLapSpeed, statusId] \\n\",\n \"2 constructors: [constructorId, name, nationality]; drivers: [driverId, driverRef, number, code, forename, surname, nationality]; races: [raceId, year, round, name, date]; constructorResults: [constructorResultsId, raceId, constructorId, points, status]; constructorStandings: [constructorStandingsId, raceId, constructorId, points, position, positionText, wins]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, points, position, positionText, statusId] \\n\",\n \"3 circuits: [circuitId, name, location, country, lat, lng, alt, url]; constructors: [constructorId, name, nationality, url]; drivers: [driverId, driverRef, number, code, forename, surname, nationality, url]; seasons: [year, url]; races: [raceId, year, round, circuitId, name, date, url]; status: [statusId, status] \\n\",\n \"4 drivers: [driverId, driverRef, number, code, forename, surname, dob, nationality]; races: [raceId, year, round, name, date]; driverStandings: [driverStandingsId, raceId, driverId, points, position, positionText, wins]; results: [resultId, raceId, driverId, constructorId, number, grid, position, positionText, positionOrder, points, laps, statusId] \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"=== Quality Comparison ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
MetricOLDNEWThresholdStatus
0Roles55NaNNaN
1Avg Coverage65.5%55.3%<85%OK
2Coverage Std0.1830.251>0.065OK
3Max Overlap87.3%57.4%<80%OK
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Metric OLD NEW Threshold Status\\n\",\n \"0 Roles 5 5 NaN NaN\\n\",\n \"1 Avg Coverage 65.5% 55.3% <85% OK\\n\",\n \"2 Coverage Std 0.183 0.251 >0.065 OK\\n\",\n \"3 Max Overlap 87.3% 57.4% <80% OK\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[OK] formula_1: All quality checks passed\\n\",\n \"\\n\",\n \"======================================================================\\n\",\n \"[DECISION] Satisfied? Run Cell 6.5 to apply. Otherwise edit Cell 6.2 and re-run 6.3.\\n\",\n \"[TIP] Use Cell 6.4.1 to select specific roles from OLD/NEW\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.4 Preview Regenerated Roles (Compare OLD vs NEW + Quality Check)\\n\",\n \"# Supports multiple databases\\n\",\n \"import numpy as np\\n\",\n \"from src.role_evaluator.quality_metrics import RoleQualityEvaluator\\n\",\n \"\\n\",\n \"pd.set_option('display.max_colwidth', None)\\n\",\n \"pd.set_option('display.max_rows', None)\\n\",\n \"pd.set_option('display.width', None)\\n\",\n \"\\n\",\n \"if 'regenerated_results' in dir() and regenerated_results:\\n\",\n \" for db_name, regen_result in regenerated_results.items():\\n\",\n \" if regen_result[\\\"status\\\"] != \\\"success\\\":\\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"[SKIP] {db_name}: {regen_result.get('error', 'failed')}\\\")\\n\",\n \" continue\\n\",\n \" \\n\",\n \" regenerated_assignments = regen_result[\\\"assignments\\\"]\\n\",\n \" target_schema = target_schemas.get(db_name)\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(f\\\"Database: {db_name}\\\")\\n\",\n \" print(f\\\"{'='*70}\\\")\\n\",\n \" \\n\",\n \" # --- NEW Role Summary ---\\n\",\n \" new_summary = []\\n\",\n \" for r in regenerated_assignments:\\n\",\n \" policy = r.get('policy', {})\\n\",\n \" total_cols = count_policy_columns(policy, target_schema)\\n\",\n \" has_wc = has_wildcard_policy(policy)\\n\",\n \" cols_display = f\\\"{total_cols}\\\" + (\\\" (*)\\\" if has_wc else \\\"\\\")\\n\",\n \" policy_str = \\\"; \\\".join([\\n\",\n \" f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" \\n\",\n \" for t, c in policy.items()\\n\",\n \" ])\\n\",\n \" new_summary.append({\\n\",\n \" \\\"Role\\\": r['role'],\\n\",\n \" \\\"Description\\\": r.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Cols\\\": cols_display,\\n\",\n \" \\\"Policy\\\": policy_str\\n\",\n \" })\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n=== NEW Roles ({len(regenerated_assignments)}) ===\\\")\\n\",\n \" display(pd.DataFrame(new_summary))\\n\",\n \" \\n\",\n \" # --- Quality Metrics ---\\n\",\n \" if target_schema:\\n\",\n \" total_schema_cols = sum(len(t['columns']) for t in target_schema.values())\\n\",\n \" else:\\n\",\n \" total_schema_cols = 10\\n\",\n \" \\n\",\n \" # NEW metrics\\n\",\n \" new_coverages = [count_policy_columns(r.get('policy', {}), target_schema) / total_schema_cols \\n\",\n \" for r in regenerated_assignments]\\n\",\n \" new_avg_cov = np.mean(new_coverages)\\n\",\n \" new_cov_std = np.std(new_coverages)\\n\",\n \" \\n\",\n \" new_max_overlap = 0.0\\n\",\n \" non_admin_new = [r for r in regenerated_assignments if 'admin' not in r['role'].lower()]\\n\",\n \" for i, r1 in enumerate(non_admin_new):\\n\",\n \" set1 = RoleQualityEvaluator.policy_to_column_set(r1.get('policy', {}))\\n\",\n \" for r2 in non_admin_new[i+1:]:\\n\",\n \" set2 = RoleQualityEvaluator.policy_to_column_set(r2.get('policy', {}))\\n\",\n \" new_max_overlap = max(new_max_overlap, RoleQualityEvaluator.jaccard_similarity(set1, set2))\\n\",\n \" \\n\",\n \" # OLD metrics\\n\",\n \" old_roles = all_assignments.get('assignments', {}).get(db_name, [])\\n\",\n \" if old_roles:\\n\",\n \" old_coverages = [count_policy_columns(r.get('policy', {}), target_schema) / total_schema_cols \\n\",\n \" for r in old_roles]\\n\",\n \" old_avg_cov = np.mean(old_coverages)\\n\",\n \" old_cov_std = np.std(old_coverages)\\n\",\n \" \\n\",\n \" old_max_overlap = 0.0\\n\",\n \" non_admin_old = [r for r in old_roles if 'admin' not in r['role'].lower()]\\n\",\n \" for i, r1 in enumerate(non_admin_old):\\n\",\n \" set1 = RoleQualityEvaluator.policy_to_column_set(r1.get('policy', {}))\\n\",\n \" for r2 in non_admin_old[i+1:]:\\n\",\n \" set2 = RoleQualityEvaluator.policy_to_column_set(r2.get('policy', {}))\\n\",\n \" old_max_overlap = max(old_max_overlap, RoleQualityEvaluator.jaccard_similarity(set1, set2))\\n\",\n \" else:\\n\",\n \" old_avg_cov, old_cov_std, old_max_overlap = 0, 0, 0\\n\",\n \" \\n\",\n \" # Comparison table (using QUALITY_THRESHOLDS from Cell 5.1)\\n\",\n \" def status(metric, val):\\n\",\n \" if metric == \\\"Coverage\\\": \\n\",\n \" return \\\"WARN\\\" if val > QUALITY_THRESHOLDS.get(\\\"coverage_max\\\", 0.90) else \\\"OK\\\"\\n\",\n \" if metric == \\\"CovStd\\\": \\n\",\n \" return \\\"WARN\\\" if val < QUALITY_THRESHOLDS.get(\\\"coverage_std_min\\\", 0.08) else \\\"OK\\\"\\n\",\n \" if metric == \\\"MaxOverlap\\\": \\n\",\n \" return \\\"WARN\\\" if val > QUALITY_THRESHOLDS.get(\\\"max_overlap\\\", 0.80) else \\\"OK\\\"\\n\",\n \" return \\\"OK\\\"\\n\",\n \" \\n\",\n \" quality_df = pd.DataFrame([\\n\",\n \" {\\\"Metric\\\": \\\"Roles\\\", \\\"OLD\\\": len(old_roles), \\\"NEW\\\": len(regenerated_assignments)},\\n\",\n \" {\\\"Metric\\\": \\\"Avg Coverage\\\", \\\"OLD\\\": f\\\"{old_avg_cov:.1%}\\\", \\\"NEW\\\": f\\\"{new_avg_cov:.1%}\\\", \\n\",\n \" \\\"Threshold\\\": f\\\"<{QUALITY_THRESHOLDS.get('coverage_max', 0.90):.0%}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"Coverage\\\", new_avg_cov)},\\n\",\n \" {\\\"Metric\\\": \\\"Coverage Std\\\", \\\"OLD\\\": f\\\"{old_cov_std:.3f}\\\", \\\"NEW\\\": f\\\"{new_cov_std:.3f}\\\",\\n\",\n \" \\\"Threshold\\\": f\\\">{QUALITY_THRESHOLDS.get('coverage_std_min', 0.08)}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"CovStd\\\", new_cov_std)},\\n\",\n \" {\\\"Metric\\\": \\\"Max Overlap\\\", \\\"OLD\\\": f\\\"{old_max_overlap:.1%}\\\", \\\"NEW\\\": f\\\"{new_max_overlap:.1%}\\\",\\n\",\n \" \\\"Threshold\\\": f\\\"<{QUALITY_THRESHOLDS.get('max_overlap', 0.80):.0%}\\\",\\n\",\n \" \\\"Status\\\": status(\\\"MaxOverlap\\\", new_max_overlap)},\\n\",\n \" ])\\n\",\n \" print(\\\"\\\\n=== Quality Comparison ===\\\")\\n\",\n \" display(quality_df)\\n\",\n \" \\n\",\n \" warn_count = quality_df['Status'].eq('WARN').sum() if 'Status' in quality_df.columns else 0\\n\",\n \" if warn_count == 0:\\n\",\n \" print(f\\\"[OK] {db_name}: All quality checks passed\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\"[WARN] {db_name}: {warn_count} issue(s)\\\")\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n{'='*70}\\\")\\n\",\n \" print(\\\"[DECISION] Satisfied? Run Cell 6.5 to apply. Otherwise edit Cell 6.2 and re-run 6.3.\\\")\\n\",\n \" print(\\\"[TIP] Use Cell 6.4.1 to select specific roles from OLD/NEW\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[WARN] No regenerated results. Run Cell 6.3 first.\\\")\\n\",\n \"\\n\",\n \"pd.reset_option('display.max_colwidth')\\n\",\n \"pd.reset_option('display.max_rows')\\n\",\n \"pd.reset_option('display.width')\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 70,\n \"id\": \"f003a014\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Role Selection Summary ===\\n\",\n \"\\n\",\n \"============================================================\\n\",\n \"Database: formula_1\\n\",\n \" From OLD (0): (none)\\n\",\n \" From NEW (4): ['SystemManager', 'RaceAnalyst', 'PublicRelations', 'DriverManager']\\n\",\n \" Combined: 4 roles\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
SourceRoleDescriptionTablesPolicy
0NEWSystemManagerFull administrative access for system maintena...13circuits: [*]; constructors: [*]; drivers: [*]...
1NEWRaceAnalystAnalyzes race performance data including lap t...8circuits: [circuitId, name, location, country,...
2NEWPublicRelationsAccesses public information about circuits, dr...6circuits: [circuitId, name, location, country,...
3NEWDriverManagerManages driver information and personal detail...4drivers: [driverId, driverRef, number, code, f...
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Source Role Description \\\\\\n\",\n \"0 NEW SystemManager Full administrative access for system maintena... \\n\",\n \"1 NEW RaceAnalyst Analyzes race performance data including lap t... \\n\",\n \"2 NEW PublicRelations Accesses public information about circuits, dr... \\n\",\n \"3 NEW DriverManager Manages driver information and personal detail... \\n\",\n \"\\n\",\n \" Tables Policy \\n\",\n \"0 13 circuits: [*]; constructors: [*]; drivers: [*]... \\n\",\n \"1 8 circuits: [circuitId, name, location, country,... \\n\",\n \"2 6 circuits: [circuitId, name, location, country,... \\n\",\n \"3 4 drivers: [driverId, driverRef, number, code, f... \"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"============================================================\\n\",\n \"[NEXT] Run Cell 6.5 to apply combined role sets\\n\",\n \"[TIP] Edit ROLE_SELECTION above to customize, then re-run this cell\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.4.1 Select & Combine Roles from OLD and NEW\\n\",\n \"# Human expert picks best roles from both versions to create final role set\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# EDIT HERE: Specify which roles to keep from each version\\n\",\n \"# Format: {\\\"db_name\\\": {\\\"old\\\": [role_names], \\\"new\\\": [role_names]}}\\n\",\n \"# Leave empty [] to skip a version, or use [\\\"*\\\"] to keep all from that version\\n\",\n \"# ============================================================\\n\",\n \"ROLE_SELECTION = {\\n\",\n \" \\\"formula_1\\\": {\\n\",\n \" \\\"old\\\": [], # e.g., [\\\"DataAnalyst\\\", \\\"Researcher\\\"]\\n\",\n \" \\\"new\\\": [\\\"SystemManager\\\", \\\"RaceAnalyst\\\", \\\"PublicRelations\\\", \\\"DriverManager\\\"], # keep all new roles\\n\",\n \" },\\n\",\n \" # \\\"financial\\\": {\\n\",\n \" # \\\"old\\\": [],\\n\",\n \" # \\\"new\\\": [\\\"*\\\"],\\n\",\n \" # },\\n\",\n \"}\\n\",\n \"\\n\",\n \"# ============================================================\\n\",\n \"# Process selections and create combined role sets\\n\",\n \"# ============================================================\\n\",\n \"combined_results = {}\\n\",\n \"\\n\",\n \"if 'regenerated_results' in dir() and regenerated_results:\\n\",\n \" print(\\\"=== Role Selection Summary ===\\\\n\\\")\\n\",\n \" \\n\",\n \" for db_name in valid_target_dbs:\\n\",\n \" selection = ROLE_SELECTION.get(db_name, {\\\"old\\\": [], \\\"new\\\": [\\\"*\\\"]})\\n\",\n \" old_keep = selection.get(\\\"old\\\", [])\\n\",\n \" new_keep = selection.get(\\\"new\\\", [\\\"*\\\"])\\n\",\n \" \\n\",\n \" # Get OLD roles\\n\",\n \" old_roles = all_assignments.get('assignments', {}).get(db_name, [])\\n\",\n \" old_role_dict = {r['role']: r for r in old_roles}\\n\",\n \" \\n\",\n \" # Get NEW roles\\n\",\n \" regen_result = regenerated_results.get(db_name, {})\\n\",\n \" if regen_result.get(\\\"status\\\") != \\\"success\\\":\\n\",\n \" print(f\\\"[SKIP] {db_name}: regeneration failed\\\")\\n\",\n \" continue\\n\",\n \" new_roles = regen_result[\\\"assignments\\\"]\\n\",\n \" new_role_dict = {r['role']: r for r in new_roles}\\n\",\n \" \\n\",\n \" # Build combined role set\\n\",\n \" combined_roles = []\\n\",\n \" selected_from_old = []\\n\",\n \" selected_from_new = []\\n\",\n \" \\n\",\n \" # Select from OLD\\n\",\n \" if old_keep == [\\\"*\\\"]:\\n\",\n \" combined_roles.extend(old_roles)\\n\",\n \" selected_from_old = [r['role'] for r in old_roles]\\n\",\n \" else:\\n\",\n \" for role_name in old_keep:\\n\",\n \" if role_name in old_role_dict:\\n\",\n \" combined_roles.append(old_role_dict[role_name])\\n\",\n \" selected_from_old.append(role_name)\\n\",\n \" else:\\n\",\n \" print(f\\\" [WARN] {db_name}: OLD role '{role_name}' not found\\\")\\n\",\n \" \\n\",\n \" # Select from NEW\\n\",\n \" if new_keep == [\\\"*\\\"]:\\n\",\n \" combined_roles.extend(new_roles)\\n\",\n \" selected_from_new = [r['role'] for r in new_roles]\\n\",\n \" else:\\n\",\n \" for role_name in new_keep:\\n\",\n \" if role_name in new_role_dict:\\n\",\n \" combined_roles.append(new_role_dict[role_name])\\n\",\n \" selected_from_new.append(role_name)\\n\",\n \" else:\\n\",\n \" print(f\\\" [WARN] {db_name}: NEW role '{role_name}' not found\\\")\\n\",\n \" \\n\",\n \" combined_results[db_name] = combined_roles\\n\",\n \" \\n\",\n \" # Display summary\\n\",\n \" print(f\\\"{'='*60}\\\")\\n\",\n \" print(f\\\"Database: {db_name}\\\")\\n\",\n \" print(f\\\" From OLD ({len(selected_from_old)}): {selected_from_old if selected_from_old else '(none)'}\\\")\\n\",\n \" print(f\\\" From NEW ({len(selected_from_new)}): {selected_from_new if selected_from_new else '(none)'}\\\")\\n\",\n \" print(f\\\" Combined: {len(combined_roles)} roles\\\")\\n\",\n \" \\n\",\n \" # Show combined roles table\\n\",\n \" target_schema = target_schemas.get(db_name)\\n\",\n \" combined_summary = []\\n\",\n \" for r in combined_roles:\\n\",\n \" policy = r.get('policy', {})\\n\",\n \" source = \\\"OLD\\\" if r['role'] in old_role_dict and r['role'] not in [nr['role'] for nr in new_roles] else \\\"NEW\\\"\\n\",\n \" if r['role'] in old_role_dict and r['role'] in [nr['role'] for nr in new_roles]:\\n\",\n \" source = \\\"NEW\\\" # Prefer NEW if same name exists in both\\n\",\n \" combined_summary.append({\\n\",\n \" \\\"Source\\\": source,\\n\",\n \" \\\"Role\\\": r['role'],\\n\",\n \" \\\"Description\\\": r.get('description', ''),\\n\",\n \" \\\"Tables\\\": len(policy),\\n\",\n \" \\\"Policy\\\": \\\"; \\\".join([f\\\"{t}: [{', '.join(c) if isinstance(c, list) else c}]\\\" for t, c in policy.items()])\\n\",\n \" })\\n\",\n \" \\n\",\n \" display(pd.DataFrame(combined_summary))\\n\",\n \" print()\\n\",\n \" \\n\",\n \" print(\\\"=\\\"*60)\\n\",\n \" print(f\\\"[NEXT] Run Cell 6.5 to apply combined role sets\\\")\\n\",\n \" print(\\\"[TIP] Edit ROLE_SELECTION above to customize, then re-run this cell\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[WARN] No regenerated results. Run Cell 6.3 first.\\\")\\n\",\n \" print(\\\"\\\\n[HINT] Available roles to select from:\\\")\\n\",\n \" print(\\\" OLD: roles from current assignments\\\")\\n\",\n \" print(\\\" NEW: roles from regeneration\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 71,\n \"id\": \"6cb24c7d\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"[MODE] Applying COMBINED role sets (from Cell 6.4.1 selection)\\n\",\n \"\\n\",\n \"=== Changes Applied ===\\n\"\n ]\n },\n {\n \"data\": {\n \"text/html\": [\n \"
\\n\",\n \"\\n\",\n \"\\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \" \\n\",\n \"
DatabaseOld RolesNew RolesSource
0formula_154Combined (OLD+NEW)
\\n\",\n \"
\"\n ],\n \"text/plain\": [\n \" Database Old Roles New Roles Source\\n\",\n \"0 formula_1 5 4 Combined (OLD+NEW)\"\n ]\n },\n \"metadata\": {},\n \"output_type\": \"display_data\"\n },\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"\\n\",\n \"Saved to: bird_column_level_rbac_assignments_v2_20251230.json\\n\",\n \"\\n\",\n \"[OK] State cleared. Select new database(s) to continue.\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.5 Apply Changes (Save Combined Role Sets)\\n\",\n \"# Uses combined_results from Cell 6.4.1 (selected from OLD + NEW)\\n\",\n \"from datetime import datetime\\n\",\n \"\\n\",\n \"APPLY_CHANGES = True # Set to True to confirm\\n\",\n \"\\n\",\n \"if APPLY_CHANGES:\\n\",\n \" # Prefer combined_results (from selection), fallback to regenerated_results\\n\",\n \" use_combined = 'combined_results' in dir() and combined_results\\n\",\n \" use_regenerated = 'regenerated_results' in dir() and regenerated_results\\n\",\n \" \\n\",\n \" if use_combined:\\n\",\n \" print(\\\"[MODE] Applying COMBINED role sets (from Cell 6.4.1 selection)\\\\n\\\")\\n\",\n \" applied = []\\n\",\n \" \\n\",\n \" for db_name, combined_roles in combined_results.items():\\n\",\n \" if not combined_roles:\\n\",\n \" continue\\n\",\n \" \\n\",\n \" old_count = len(all_assignments.get('assignments', {}).get(db_name, []))\\n\",\n \" all_assignments['assignments'][db_name] = combined_roles\\n\",\n \" applied.append({\\n\",\n \" \\\"Database\\\": db_name,\\n\",\n \" \\\"Old Roles\\\": old_count,\\n\",\n \" \\\"New Roles\\\": len(combined_roles),\\n\",\n \" \\\"Source\\\": \\\"Combined (OLD+NEW)\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" if applied:\\n\",\n \" OUTPUT_DIR = project_root / 'outputs'\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = OUTPUT_DIR / f'bird_column_level_rbac_assignments_v2_{today}.json'\\n\",\n \" with open(output_path, 'w') as f:\\n\",\n \" json.dump(all_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \" \\n\",\n \" print(\\\"=== Changes Applied ===\\\")\\n\",\n \" display(pd.DataFrame(applied))\\n\",\n \" print(f\\\"\\\\nSaved to: {output_path.name}\\\")\\n\",\n \" \\n\",\n \" # Clear state\\n\",\n \" combined_results = {}\\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"\\\\n[OK] State cleared. Select new database(s) to continue.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No combined role sets to apply. Run Cell 6.4.1 first.\\\")\\n\",\n \" \\n\",\n \" elif use_regenerated:\\n\",\n \" print(\\\"[MODE] Applying ALL NEW roles (no selection made)\\\\n\\\")\\n\",\n \" applied = []\\n\",\n \" \\n\",\n \" for db_name, regen_result in regenerated_results.items():\\n\",\n \" if regen_result[\\\"status\\\"] != \\\"success\\\":\\n\",\n \" continue\\n\",\n \" \\n\",\n \" old_count = len(all_assignments.get('assignments', {}).get(db_name, []))\\n\",\n \" all_assignments['assignments'][db_name] = regen_result[\\\"assignments\\\"]\\n\",\n \" applied.append({\\n\",\n \" \\\"Database\\\": db_name,\\n\",\n \" \\\"Old Roles\\\": old_count,\\n\",\n \" \\\"New Roles\\\": len(regen_result[\\\"assignments\\\"]),\\n\",\n \" \\\"Source\\\": \\\"All NEW\\\"\\n\",\n \" })\\n\",\n \" \\n\",\n \" if applied:\\n\",\n \" OUTPUT_DIR = project_root / 'outputs'\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = OUTPUT_DIR / f'bird_column_level_rbac_assignments_v2_{today}.json'\\n\",\n \" with open(output_path, 'w') as f:\\n\",\n \" json.dump(all_assignments, f, indent=2, ensure_ascii=False)\\n\",\n \" \\n\",\n \" print(\\\"=== Changes Applied ===\\\")\\n\",\n \" display(pd.DataFrame(applied))\\n\",\n \" print(f\\\"\\\\nSaved to: {output_path.name}\\\")\\n\",\n \" \\n\",\n \" regenerated_results = {}\\n\",\n \" print(\\\"\\\\n[OK] State cleared. Select new database(s) to continue.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No successful regenerations to apply.\\\")\\n\",\n \" else:\\n\",\n \" print(\\\"[WARN] No results to apply. Run Cell 6.3 and optionally Cell 6.4.1 first.\\\")\\n\",\n \"else:\\n\",\n \" has_combined = 'combined_results' in dir() and combined_results\\n\",\n \" has_regenerated = 'regenerated_results' in dir() and regenerated_results\\n\",\n \" \\n\",\n \" if has_combined:\\n\",\n \" print(f\\\"[INFO] {len(combined_results)} database(s) with COMBINED role sets ready\\\")\\n\",\n \" print(\\\"[TIP] These are your custom selections from OLD + NEW\\\")\\n\",\n \" elif has_regenerated:\\n\",\n \" success_count = sum(1 for r in regenerated_results.values() if r[\\\"status\\\"] == \\\"success\\\")\\n\",\n \" print(f\\\"[INFO] {success_count} database(s) with ALL NEW roles ready\\\")\\n\",\n \" print(\\\"[TIP] Run Cell 6.4.1 to select specific roles from OLD/NEW\\\")\\n\",\n \" \\n\",\n \" print(\\\"\\\\n[INFO] APPLY_CHANGES is False. Set to True and re-run to apply.\\\")\"\n ]\n },\n {\n \"cell_type\": \"code\",\n \"execution_count\": 72,\n \"id\": \"f1bd0bc2\",\n \"metadata\": {},\n \"outputs\": [\n {\n \"name\": \"stdout\",\n \"output_type\": \"stream\",\n \"text\": [\n \"=== Regenerating RBAC Dataset ===\\n\",\n \"Role assignments: bird_column_level_rbac_assignments_v2_20251230.json\\n\",\n \"BIRD data: /home/feiy/Role-SQL-benchmark/data/Bird/dev_20251106/dev.json\\n\",\n \"Generating column-level RBAC dataset...\\n\",\n \" Roles per DB: None\\n\",\n \" Queries per role: all\\n\",\n \"Current ratio (allowed): 50.41%\\n\",\n \" Allowed: 3656, Denied: 3596\\n\",\n \"\\n\",\n \"Dataset saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251230.json\\n\",\n \"Metadata saved to /home/feiy/Role-SQL-benchmark/outputs/column_level_rbac_dataset_bird_20251230_metadata.json\\n\",\n \" Total entries: 7252\\n\",\n \" Allowed: 3656 (50.4%)\\n\",\n \" Denied: 3596 (49.6%)\\n\",\n \"\\n\",\n \"✓ Dataset saved to: column_level_rbac_dataset_bird_20251230.json\\n\",\n \"\\n\",\n \"=== Dataset Statistics ===\\n\",\n \" total_entries: 7252\\n\",\n \" allowed: 3656\\n\",\n \" denied: 3596\\n\",\n \" allowed_ratio: 0.5041367898510756\\n\",\n \"\\n\",\n \"Per-database distribution:\\n\",\n \" california_schools: allowed=118, denied=327\\n\",\n \" card_games: allowed=507, denied=448\\n\",\n \" codebase_community: allowed=578, denied=352\\n\",\n \" debit_card_specializing: allowed=174, denied=210\\n\",\n \" european_football_2: allowed=277, denied=368\\n\",\n \" financial: allowed=156, denied=374\\n\",\n \" formula_1: allowed=385, denied=311\\n\",\n \" student_club: allowed=396, denied=394\\n\",\n \" superhero: allowed=328, denied=317\\n\",\n \" thrombosis_prediction: allowed=432, denied=220\\n\",\n \" toxicology: allowed=305, denied=275\\n\"\n ]\n }\n ],\n \"source\": [\n \"# 6.6 Regenerate RBAC Dataset with Updated Role Assignments\\n\",\n \"# Run this after Cell 6.5 to create the final dataset\\n\",\n \"\\n\",\n \"from datetime import datetime\\n\",\n \"import importlib\\n\",\n \"\\n\",\n \"# IMPORTANT: Reload ALL dependent modules to pick up CTE parsing fix\\n\",\n \"import src.processors.column_extractor\\n\",\n \"import src.processors.column_permission_checker\\n\",\n \"import src.processors.column_level_rbac_generator\\n\",\n \"\\n\",\n \"importlib.reload(src.processors.column_extractor)\\n\",\n \"importlib.reload(src.processors.column_permission_checker)\\n\",\n \"importlib.reload(src.processors.column_level_rbac_generator)\\n\",\n \"\\n\",\n \"from src.processors.column_level_rbac_generator import ColumnLevelRBACGenerator\\n\",\n \"\\n\",\n \"# Find the updated role assignments file (v2 if exists, otherwise latest)\\n\",\n \"v2_files = sorted(glob.glob(str(project_root / 'outputs' / 'bird_column_level_rbac_assignments_v2_*.json')))\\n\",\n \"if v2_files:\\n\",\n \" UPDATED_ROLE_PATH = v2_files[-1]\\n\",\n \"else:\\n\",\n \" role_files = sorted(glob.glob(str(project_root / 'outputs' / 'column_level_role_assignments_bird_*.json')))\\n\",\n \" UPDATED_ROLE_PATH = role_files[-1] if role_files else None\\n\",\n \"\\n\",\n \"if UPDATED_ROLE_PATH:\\n\",\n \" print(f\\\"=== Regenerating RBAC Dataset ===\\\")\\n\",\n \" print(f\\\"Role assignments: {Path(UPDATED_ROLE_PATH).name}\\\")\\n\",\n \" print(f\\\"BIRD data: {BIRD_DATA_PATH}\\\")\\n\",\n \" \\n\",\n \" # Initialize generator with updated roles\\n\",\n \" generator = ColumnLevelRBACGenerator(\\n\",\n \" role_assignments_path=UPDATED_ROLE_PATH,\\n\",\n \" bird_data_path=str(BIRD_DATA_PATH),\\n\",\n \" bird_db_root=str(BIRD_DB_ROOT),\\n\",\n \" project_root=str(project_root),\\n\",\n \" seed=42\\n\",\n \" )\\n\",\n \" \\n\",\n \" # Generate dataset\\n\",\n \" today = datetime.now().strftime('%Y%m%d')\\n\",\n \" output_path = project_root / 'outputs' / f'column_level_rbac_dataset_bird_{today}.json'\\n\",\n \" \\n\",\n \" full_stats = generator.generate_and_save(\\n\",\n \" output_path=str(output_path),\\n\",\n \" roles_per_db=None,\\n\",\n \" queries_per_role=None\\n\",\n \" )\\n\",\n \" \\n\",\n \" print(f\\\"\\\\n✓ Dataset saved to: {output_path.name}\\\")\\n\",\n \" print(f\\\"\\\\n=== Dataset Statistics ===\\\")\\n\",\n \" for k, v in full_stats.items():\\n\",\n \" if k == 'by_database':\\n\",\n \" print(f\\\"\\\\nPer-database distribution:\\\")\\n\",\n \" for db_id, counts in sorted(v.items()):\\n\",\n \" print(f\\\" {db_id}: allowed={counts['allowed']}, denied={counts['denied']}\\\")\\n\",\n \" else:\\n\",\n \" print(f\\\" {k}: {v}\\\")\\n\",\n \"else:\\n\",\n \" print(\\\"[ERROR] No role assignments file found. Run Cell 6.5 first.\\\")\"\n ]\n },\n {\n \"cell_type\": \"markdown\",\n \"id\": \"a9345c97\",\n \"metadata\": {},\n \"source\": [\n \"## 7. Summary\\n\",\n \"\\n\",\n \"### Generated Files\\n\",\n \"- `outputs/column_level_role_assignments_bird_YYYYMMDD.json` - Role assignments with column-level policies\\n\",\n \"- `outputs/bird_column_level_rbac_assignments_v2_YYYYMMDD.json` - Updated role assignments after regeneration\\n\",\n \"- `outputs/column_level_rbac_dataset_bird_YYYYMMDD.json` - Column-Level RBAC dataset\\n\",\n \"\\n\",\n \"### Workflow\\n\",\n \"\\n\",\n \"| Section | Description |\\n\",\n \"|---------|-------------|\\n\",\n \"| **3** | Batch process all BIRD databases to generate initial roles |\\n\",\n \"| **4** | Generate RBAC dataset from role assignments |\\n\",\n \"| **5** | Quality assessment with configurable thresholds |\\n\",\n \"| **6.1** | Select problematic database(s) and view current state |\\n\",\n \"| **6.2** | Write regeneration hints with problem description |\\n\",\n \"| **6.3** | Execute LLM regeneration with hints |\\n\",\n \"| **6.4** | Preview OLD vs NEW roles with quality comparison |\\n\",\n \"| **6.4.1** | Select & combine best roles from OLD and NEW |\\n\",\n \"| **6.5** | Apply changes (save updated role assignments) |\\n\",\n \"| **6.6** | Regenerate RBAC dataset with updated roles |\\n\",\n \"\\n\",\n \"### Quality Assessment Module (Section 5)\\n\",\n \"\\n\",\n \"```python\\n\",\n \"from src.role_evaluator import RoleQualityEvaluator, RoleQualityVisualizer\\n\",\n \"\\n\",\n \"evaluator = RoleQualityEvaluator(\\n\",\n \" role_assignments_path=\\\"outputs/column_level_role_assignments_bird.json\\\",\\n\",\n \" dataset_path=\\\"outputs/column_level_rbac_dataset_bird.json\\\",\\n\",\n \" schema_dir=\\\"data/Bird/dev_20251106/dev_databases\\\",\\n\",\n \" embed_model=\\\"BAAI/bge-small-en-v1.5\\\" # or \\\"text-embedding-3-small\\\"\\n\",\n \")\\n\",\n \"\\n\",\n \"report = evaluator.evaluate_all()\\n\",\n \"visualizer = RoleQualityVisualizer(evaluator=evaluator, report=report)\\n\",\n \"visualizer.plot_quality_dashboard()\\n\",\n \"```\\n\",\n \"\\n\",\n \"### Quality Thresholds (Configurable)\\n\",\n \"\\n\",\n \"| Metric | Default | Description |\\n\",\n \"|--------|---------|-------------|\\n\",\n \"| `deny_rate_min` | 5% | Warn if deny rate below (roles too permissive) |\\n\",\n \"| `coverage_max` | 90% | Warn if avg coverage above (roles too broad) |\\n\",\n \"| `coverage_std_min` | 0.08 | Warn if coverage std below (low diversity) |\\n\",\n \"| `max_overlap` | 80% | Warn if max overlap above (redundant roles) |\\n\",\n \"\\n\",\n \"### External Modules\\n\",\n \"\\n\",\n \"1. **`src/role_evaluator/quality_metrics.py`** - Quality metrics computation\\n\",\n \" - `RoleQualityEvaluator`: Comprehensive evaluator\\n\",\n \" - `DenyRateMetrics`, `SemanticMetrics`, `OverlapMetrics`: Data classes\\n\",\n \" - `print_quality_report()`: Formatted report output\\n\",\n \"\\n\",\n \"2. **`src/role_evaluator/quality_visualizer.py`** - Visualization suite\\n\",\n \" - `plot_deny_rate_distribution()`: Permission distribution chart\\n\",\n \" - `plot_semantic_alignment()`: Semantic alignment scatter plot\\n\",\n \" - `plot_policy_overlap_bars()`: Policy overlap bar chart\\n\",\n \" - `plot_quality_dashboard()`: Comprehensive dashboard\\n\",\n \"\\n\",\n \"3. **`src/processors/column_level_rbac_generator.py`** - Dataset generation\\n\",\n \" - `ColumnLevelRBACGenerator`: Generate RBAC dataset from role assignments\"\n ]\n }\n ],\n \"metadata\": {\n \"kernelspec\": {\n \"display_name\": \"llm4db\",\n \"language\": \"python\",\n \"name\": \"python3\"\n },\n \"language_info\": {\n \"codemirror_mode\": {\n \"name\": \"ipython\",\n \"version\": 3\n },\n \"file_extension\": \".py\",\n \"mimetype\": \"text/x-python\",\n \"name\": \"python\",\n \"nbconvert_exporter\": \"python\",\n \"pygments_lexer\": \"ipython3\",\n \"version\": \"3.10.18\"\n }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"}}}}