from __future__ import annotations import re from .models import FailureReport _SECRET_PATTERNS = ( ( re.compile(r"(?i)\b(?:mysql|mariadb|postgres(?:ql)?|sqlserver)://[^\s]+"), "[DATABASE_URL]", ), (re.compile(r"(?i)(password|passwd|secret|token|api[_ -]?key)\s*[:=]\s*\S+"), r"\1=[REDACTED]"), (re.compile(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b"), "[EMAIL]"), (re.compile(r"\b(?:\d{1,3}\.){3}\d{1,3}\b"), "[IP]"), (re.compile(r"(?i)bearer\s+[A-Za-z0-9._~+/=-]+"), "Bearer [REDACTED]"), (re.compile(r"\bAKIA[0-9A-Z]{16}\b"), "[AWS_KEY]"), (re.compile(r"-----BEGIN [A-Z ]+KEY-----[\s\S]+?-----END [A-Z ]+KEY-----"), "[PRIVATE_KEY]"), (re.compile(r"\b[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b"), "[JWT]"), ) _REPOSITORY_PLAYBOOK = """ Repository ownership map: - app/Services/SQLGeneratorService.php assembles live schema and business context for SQL generation. - config/erp_semantics.php owns ERP joins, metrics, formulas, filters, and reference examples. - config/cockpit_semantics.php owns device and customer-database semantics. - app/Services/AIService.php owns provider calls, pseudonymization boundaries, and response parsing. - app/Services/TenantDatabaseService.php owns ERP/config/customer source selection and tenant metadata. - app/Services/SQLValidatorService.php owns read-only SQL safety; do not weaken it to accept a fix. - app/Http/Controllers/ChatController.php orchestrates routing, execution, answers, and diagnostics. - app/Services/FailureTrackingService.php and FailureAutomationService.php own failure handoff. - tests/Unit is preferred for deterministic service/context rules; tests/Feature is for HTTP, persistence, authorization, or real isolated-database behavior. Repair workflow: 1. Inspect the owning implementation, its configuration, and the nearest existing test first. 2. State one root-cause hypothesis and make the smallest change that can prove it. 3. Put reusable business knowledge in tracked semantics configuration, not question-specific code. 4. A prompt/context fix must test the real generated context. A deterministic SQL builder must test its exact SQL and execute it against synthetic fixtures when useful. 5. Tests must contain assertions that execute; reject empty loops and broad unrelated fallbacks. 6. Do not expose protected production methods publicly for tests. Use a test-only subclass. 7. Do not duplicate one rule in service code and semantics config, or add explanatory comments for self-evident test setup. 8. Inspect the final diff for malformed edits, unrelated files, hardcoded report values, and tests that pass without exercising the changed behavior. """ def redact(value: str | None) -> str: result = value or "" for pattern, replacement in _SECRET_PATTERNS: result = pattern.sub(replacement, result) return result[:12_000] def build_task(report: FailureReport) -> str: prompt = redact(report.prompt) feedback = redact(report.user_feedback) expected_behavior = redact(report.expected_behavior) response = redact(report.response) error = redact(report.error_message) sql = redact(report.sql_query) tenant_scope = '' if report.context.get('database_type') == 'customer': tenant_scope = """ Tenant routing fact: The customer has already selected one tenant database. SQL inside that database must not invent an additional customer discriminator column. Use only columns present in tracked schema/semantics, and fix SQL-generation guidance rather than rewriting one unknown column to another guessed column. TenantDatabaseService records the explicit source type in database.connections..tenant_type; use that metadata instead of database-name patterns or heuristics. """ sql_semantics = '' if report.category in {'incorrect_answer', 'sql_execution'}: sql_semantics = """ SQL repair guidance: When the SQL is syntactically valid but uses the wrong business calculation, prefer adding or correcting tracked domain knowledge in config/*_semantics.php so the schema prompt teaches the model the right joins, filters, and formula. Do not hardcode one user's question or article ID in SQLGeneratorService, and do not add post-generation replacement of guessed SQL. For regression coverage of prompt guidance, expose the relevant protected schema/business- context builder through a test subclass and assert that its real output contains the required formula and rules. Do not mock AIService to return the known-bad SQL and then expect prompt guidance to rewrite that mocked response. Keep database fixture tests only when production code itself deterministically builds and executes the SQL under test. """ return f"""You are fixing failure report #{report.id} in the Laravel AI Chat repository. {_REPOSITORY_PLAYBOOK} Rules: - First add a regression test that reproduces the reported behavior. - The regression test must execute the relevant production behavior; never mock or stub the behavior being tested. - Make the smallest production change that fixes the root cause. - Preserve read-only SQL validation and tenant isolation. - Never read or modify .env files, credentials, deployment secrets, or production data. - Do not weaken tests, authentication, authorization, SQL validation, or safety checks. - Do not commit or push; the orchestrator owns Git publication. Failure category: {report.category} Feedback type: {report.feedback_type or 'not specified'} Source: {report.source} Model: {redact(str(report.context.get('model', 'unknown')))} Database type: {redact(str(report.context.get('database_type', 'unknown')))} User request: {prompt or '[not available]'} User feedback: {feedback or '[not available]'} Expected behavior: {expected_behavior or '[not available]'} Observed answer: {response or '[not available]'} Observed error: {error or '[not available]'} Generated SQL, if relevant: {sql or '[not available]'} {tenant_scope} {sql_semantics} Run focused tests while working. Leave the repository with the fix and regression test applied. """ def build_retry_task(report: FailureReport, exception: Exception) -> str: failure = redact(str(exception))[-6_000:] return build_task(report) + f""" The previous implementation failed isolated validation. Correct the existing changes using this test output: {failure} Keep the regression test meaningful. Do not remove or weaken tests, safety checks, authentication, authorization, SQL validation, or tenant isolation. If a new test calls an unrelated specialized code path that correctly returns no result, repair the test to exercise the owning production behavior; never broaden unrelated production routing merely to make the test pass. Do not commit or push. """