toContain("case 'xlvask-automation-migrate':") ->toContain("require_once 'cron/EnsureXLVaskAutomationSchema.php'"); }); it('keeps the cron entry point gated by the WD constant and the migration class', function (): void { $cron = file_get_contents(WD . '/cron/EnsureXLVaskAutomationSchema.php'); expect($cron) ->toContain("if (!defined('WD'))") ->toContain('migration_20260804_xlvask_ai_auto_policy_v2::preflight') ->toContain('migration_20260804_xlvask_ai_auto_policy_v2::apply') ->toContain('xlvask_usage_logs_schema_bootstrap::applyWashIdUniquenessMigration'); }); it('keeps the migration class operator-only and references the bootstrap entry point', function (): void { $migration = file_get_contents(WD . '/modules/xlvask/migrations/20260804_xlvask_ai_auto_policy_v2.php'); expect($migration) ->toContain('operator-invoked') ->toContain('xlvask_usage_logs_schema_bootstrap::applyExplicitMigration') ->toContain('xlvask_usage_logs_schema_bootstrap::migrationStatus'); }); it('documents both operator entry points in the XL Vask automation runbook', function (): void { $runbook = file_get_contents(WD . '/modules/xlvask/AUTOMATION_RUNBOOK.md'); expect($runbook) ->toContain('## 2. Explicit schema migration') ->toContain('## 2a. Operator entry points') ->toContain('scripts/xlvask-automation-migrate.php') ->toContain("php index.php run xlvask-automation-migrate"); }); it('keeps the standalone xlvask automation migration script gated and idempotent when the repo root is mounted', function (): void { $repoRoot = getenv('PLENO_REPO_ROOT_FOR_TESTS'); if ($repoRoot === false || $repoRoot === '') { expect(true)->toBeTrue(); // covered by CI; local docker lacks the repo-root bind mount return; } $scriptPath = realpath($repoRoot . '/scripts/xlvask-automation-migrate.php'); expect($scriptPath)->not->toBeFalse(); $source = file_get_contents($scriptPath); expect($source) ->toContain("if (PHP_SAPI !== 'cli')") ->toContain("Refusing schema mutation without: apply --yes") ->toContain('xlvask_usage_logs_schema_bootstrap::applyExplicitMigration') ->toContain('xlvask_usage_logs_schema_bootstrap::migrationStatus'); });