feat(api): standalone xlvask-automation-migrate script + runbook section (#357)
Adds `scripts/xlvask-automation-migrate.php` mirroring the existing schema-script pattern (`check` / `apply --yes`), a new AUTOMATION_RUNBOOK §2a documenting both operator entry points, and `XLVaskAutomationMigrateScriptTest` pinning the gate, the WD check, and the bootstrap references. Production autopilot-runs (POST /modules/xlvask/services/usage/autopilot-runs) was returning 500 with: ``` XL Vask automation schema is not ready. Apply migration 20260804_xlvask_ai_auto_policy_v2 explicitly. ``` because no operator had invoked the gated `applyExplicitMigration()` since PR #348 shipped the migration class. The frontend half of the fix is the companion change in pleno-vue#280 (missing `minimax_integration_enabled` key). Operator action required once merged: ``` php index.php run xlvask-automation-migrate # or php scripts/xlvask-automation-migrate.php apply --yes ``` Both produce identical JSON status; retain the artifact and rerun `check` to confirm postflight is green. Diff: +140/-0 (3 files). Tests: 87/87 XL Vask unit + 5/5 new migration script test pass.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Guard the operator entry point contract for the XL Vask automation
|
||||
* schema migration. The migration itself is intentionally operator-only
|
||||
* (see services/nginx/app/modules/xlvask/AUTOMATION_RUNBOOK.md §2), but
|
||||
* the CLI surface that wraps it must remain gated, idempotent, and
|
||||
* discoverable.
|
||||
*
|
||||
* When PLENO_REPO_ROOT_FOR_TESTS is set (the CI layout, where the repo
|
||||
* root is bind-mounted alongside services/nginx/app), the test also
|
||||
* inspects the standalone scripts/xlvask-automation-migrate.php wrapper
|
||||
* to keep it in lockstep with the cron entry point.
|
||||
*/
|
||||
|
||||
it('routes the xlvask automation migrate CLI command through the gated migration entry point', function (): void {
|
||||
$cli = file_get_contents(WD . '/cli.php');
|
||||
expect($cli)
|
||||
->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');
|
||||
});
|
||||
Reference in New Issue
Block a user