diff --git a/.env.example b/.env.example index 7fb43f1..550c8be 100644 --- a/.env.example +++ b/.env.example @@ -37,6 +37,8 @@ SESSION_DOMAIN=null BROADCAST_CONNECTION=log FILESYSTEM_DISK=local QUEUE_CONNECTION=database +# Must exceed ReplyOnMattermost / KitAgent timeout (200) so a 170s BlenderRun is not re-dispatched. +DB_QUEUE_RETRY_AFTER=240 CACHE_STORE=database # CACHE_PREFIX= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e42e499 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,72 @@ +name: CI + +# Convention-only on GitHub Free — this repo cannot require checks. +# No Blender. No Playwright. Factory hands stay on Loki. + +on: + pull_request: + push: + branches: [main] + +jobs: + tests: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: sqlite3 + coverage: none + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: vendor + key: composer-${{ hashFiles('composer.lock') }} + restore-keys: composer- + + - name: Install dependencies + run: composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: Create bootstrap and storage dirs + run: mkdir -p bootstrap/cache storage/framework/{cache,sessions,testing,views} storage/logs + + - name: Run tests + run: php artisan test --no-coverage + env: + APP_ENV: testing + APP_KEY: base64:NKGyM6eANyqn2+iiyggbXf6FNzgU98n3L/Sw1ze3v4U= + DB_CONNECTION: sqlite + DB_DATABASE: ':memory:' + QUEUE_CONNECTION: sync + CACHE_STORE: array + LOG_CHANNEL: 'null' + + pint: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + coverage: none + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: vendor + key: composer-${{ hashFiles('composer.lock') }} + restore-keys: composer- + + - name: Install dependencies + run: composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: Check code style + run: ./vendor/bin/pint --test diff --git a/AGENTS.md b/AGENTS.md index 390c782..35f6471 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,4 +8,4 @@ Loki-native factory agent. Sibling to Lexi, not a citizen in her process. - Catalog ids only. Never invent a gameplay GLB URL. - Files under ~300 lines. -Ship gate: `php artisan test`. +Ship gate: `php artisan test` + `vendor/bin/pint --test`. GitHub Actions (PHP 8.4) runs both. Required checks are convention-only on GitHub Free. No Blender / Playwright in CI. diff --git a/README.md b/README.md index 862f981..df1369b 100644 --- a/README.md +++ b/README.md @@ -78,3 +78,14 @@ php artisan serve --host=0.0.0.0 --port=8788 ``` Needs an xAI or OpenRouter key in `.env` before `kit:ask` talks. Tools and prompt dump work without one. + +## Ship gate + +```bash +php artisan test +vendor/bin/pint --test +``` + +GitHub Actions (`.github/workflows/ci.yml`) runs the same pair on PHP 8.4. No Blender, no Playwright — factory hands stay on Loki. Required-status merge-block is convention-only on GitHub Free. + +Queue knobs: `DB_QUEUE_RETRY_AFTER=240` (default in `config/queue.php`). Job / `KitAgent` / `kit-queue.service` timeout is **200s** so a 170s `BlenderRun` is not killed or re-dispatched. diff --git a/app/Agent/KitAgent.php b/app/Agent/KitAgent.php index 055cb53..0bfded4 100644 --- a/app/Agent/KitAgent.php +++ b/app/Agent/KitAgent.php @@ -12,7 +12,7 @@ use Laravel\Ai\Attributes\Timeout; use Stringable; -#[Timeout(180)] +#[Timeout(200)] class KitAgent extends BaseAgent { public function __construct(private readonly PromptBuilder $prompts) {} diff --git a/app/Jobs/ReplyOnMattermost.php b/app/Jobs/ReplyOnMattermost.php index 4ba0996..424492a 100644 --- a/app/Jobs/ReplyOnMattermost.php +++ b/app/Jobs/ReplyOnMattermost.php @@ -11,7 +11,7 @@ class ReplyOnMattermost implements ShouldQueue { use Queueable; - public int $timeout = 180; + public int $timeout = 200; public int $tries = 2; diff --git a/app/Tools/YouTubeTranscript.php b/app/Tools/YouTubeTranscript.php index a6dc7da..348d413 100644 --- a/app/Tools/YouTubeTranscript.php +++ b/app/Tools/YouTubeTranscript.php @@ -71,6 +71,7 @@ private function vttToText(string $vtt): string $line = trim($line); if (preg_match('/^(\d{2}:\d{2}:\d{2})\.\d+\s+-->/', $line, $m)) { $time = $m[1]; + continue; } if ($line === '' || str_starts_with($line, 'WEBVTT') || str_starts_with($line, 'NOTE') || preg_match('/^\d+$/', $line)) { diff --git a/config/queue.php b/config/queue.php index 79c2c0a..0251af3 100644 --- a/config/queue.php +++ b/config/queue.php @@ -40,7 +40,7 @@ 'connection' => env('DB_QUEUE_CONNECTION'), 'table' => env('DB_QUEUE_TABLE', 'jobs'), 'queue' => env('DB_QUEUE', 'default'), - 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), + 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 240), 'after_commit' => false, ], diff --git a/tests/Feature/QueueTimeoutTest.php b/tests/Feature/QueueTimeoutTest.php new file mode 100644 index 0000000..4931173 --- /dev/null +++ b/tests/Feature/QueueTimeoutTest.php @@ -0,0 +1,5 @@ +toBeGreaterThanOrEqual(240); +}); diff --git a/tests/Unit/.gitkeep b/tests/Unit/.gitkeep new file mode 100644 index 0000000..e69de29