v0.3.2 — adopt estate CI: PHPUnit suite + reusable pipeline + governance workflows

- Convert 17 hand-rolled tests to PHPUnit TestCases (tests: stubs pattern)
  P0 security tests preserved: key-leak/encryption (KeyStoreTest),
  capture-allowlist/executor-path sentinel (CaptureWriterTest)
- Add phpunit.xml.dist + update tests/bootstrap.php (Composer autoloader first)
- Add phpunit/phpunit ^9.6 + yoast/phpunit-polyfills ^2.0 to require-dev
- composer test -> vendor/bin/phpunit --configuration phpunit.xml.dist
- ci.yml: thin caller of peptide-e2e reusable CI (tests: stubs, has_js: true,
  workflow_call trigger, permissions: contents: write)
- deploy.yml: estate pattern caller of peptide-e2e deploy-app.yml@main
  (target_path: wp-content/plugins/pr-vision, gated on reusable CI)
  Pull-deploy on Hostinger stays as break-glass
- Add cto-review.yml (Haiku-only, A/B panel dropped 2026-06-12)
- Add main-push-audit.yml (direct-push tripwire)

Agent-Session: claude-adopt-ci-20260616
This commit is contained in:
peptiderepo
2026-06-16 15:25:22 +00:00
parent 1d8f024380
commit 01a9356c16
26 changed files with 2459 additions and 182 deletions

View File

@@ -0,0 +1,89 @@
<?php
/**
* Tests for PRV_Run_Lock: acquire/release/is_locked concurrency guard.
*
* @package PrVision
*/
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
/**
* @covers PRV_Run_Lock
*/
class RunLockTest extends TestCase {
protected function setUp(): void {
prv_test_reset();
if ( ! defined( 'PRV_OPENROUTER_API_KEY' ) ) {
define( 'PRV_OPENROUTER_API_KEY', 'sk-or-test-key' );
}
if ( ! defined( 'PRV_CF_ACCOUNT_ID' ) ) {
define( 'PRV_CF_ACCOUNT_ID', '' );
}
if ( ! defined( 'PRV_CF_GATEWAY_ID' ) ) {
define( 'PRV_CF_GATEWAY_ID', '' );
}
}
public function test_acquire_returns_true_when_free(): void {
$this->assertTrue( PRV_Run_Lock::acquire() );
PRV_Run_Lock::release();
}
public function test_is_locked_true_after_acquire(): void {
PRV_Run_Lock::acquire();
$this->assertTrue( PRV_Run_Lock::is_locked() );
PRV_Run_Lock::release();
}
public function test_second_acquire_returns_false(): void {
PRV_Run_Lock::acquire();
$this->assertFalse( PRV_Run_Lock::acquire() );
PRV_Run_Lock::release();
}
public function test_release_clears_lock(): void {
PRV_Run_Lock::acquire();
PRV_Run_Lock::release();
$this->assertFalse( PRV_Run_Lock::is_locked() );
}
public function test_acquire_succeeds_again_after_release(): void {
PRV_Run_Lock::acquire();
PRV_Run_Lock::release();
$this->assertTrue( PRV_Run_Lock::acquire() );
PRV_Run_Lock::release();
}
public function test_locked_since_returns_null_when_not_locked(): void {
$this->assertNull( PRV_Run_Lock::locked_since() );
}
public function test_locked_since_non_null_when_locked(): void {
PRV_Run_Lock::acquire();
$since = PRV_Run_Lock::locked_since();
$this->assertNotNull( $since );
$this->assertGreaterThanOrEqual( 0, $since );
PRV_Run_Lock::release();
}
public function test_runner_refuses_when_locked(): void {
PRV_Model_Registry::run_migration_v2();
$GLOBALS['prv_test_state']['options']['prv_peptides'] = [ [ 'slug' => 'bpc-157', 'label' => 'BPC-157' ] ];
$GLOBALS['prv_test_state']['options']['prv_prompt_intents'] = [ 'what is {peptide}' ];
PRV_Run_Lock::acquire();
$counts = ( new PRV_Probe_Runner( new PRV_Cost_Ledger() ) )->run();
$this->assertSame( 0, $counts['probed'] );
$this->assertSame( -1, $counts['skipped_error'] );
PRV_Run_Lock::release();
}
public function test_lock_released_after_runner_completes(): void {
PRV_Model_Registry::run_migration_v2();
$this->assertFalse( PRV_Run_Lock::is_locked() );
}
}