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,91 @@
<?php
/**
* Tests for provider response parsing (Perplexity + OpenRouter).
*
* @package PrVision
*/
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
/**
* @covers PRV_Perplexity_Provider
* @covers PRV_OpenRouter_Provider
*/
class ProviderParsingTest extends TestCase {
private PRV_Perplexity_Provider $perplexity;
private PRV_OpenRouter_Provider $openrouter;
protected function setUp(): void {
prv_test_reset();
$detector = new PRV_Citation_Detector();
$this->perplexity = new PRV_Perplexity_Provider( null, $detector );
$this->openrouter = new PRV_OpenRouter_Provider( 'openai/gpt-4o-search-preview', null, $detector );
}
public function test_perplexity_cited_via_citations_array(): void {
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'BPC-157 is a peptide.' ] ] ], 'citations' => [ 'https://peptiderepo.com/bpc-157/', 'https://examine.com/bpc-157' ], 'usage' => [ 'total_tokens' => 500 ] ];
$result = $this->perplexity->parse_response( $data );
$this->assertTrue( $result->is_cited() );
$this->assertSame( 1, $result->get_our_position() );
$this->assertCount( 2, $result->get_source_domains() );
$this->assertSame( 500 * 0.000001, $result->get_cost_usd() );
}
public function test_perplexity_not_cited_empty_citations(): void {
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'Info here.' ] ] ], 'citations' => [], 'usage' => [ 'total_tokens' => 200 ] ];
$result = $this->perplexity->parse_response( $data );
$this->assertFalse( $result->is_cited() );
$this->assertNull( $result->get_our_position() );
}
public function test_perplexity_excerpt_truncated_to_500_chars(): void {
$data = [ 'choices' => [ [ 'message' => [ 'content' => str_repeat( 'a', 600 ) ] ] ], 'citations' => [] ];
$result = $this->perplexity->parse_response( $data );
$this->assertSame( 500, mb_strlen( $result->get_raw_excerpt() ) );
}
public function test_perplexity_object_style_citations(): void {
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'answer' ] ] ], 'citations' => [ [ 'url' => 'https://peptiderepo.com/mk-677/' ], [ 'url' => 'https://examine.com/mk677' ] ] ];
$result = $this->perplexity->parse_response( $data );
$this->assertTrue( $result->is_cited() );
$this->assertSame( 1, $result->get_our_position() );
}
public function test_perplexity_fallback_cost_when_no_usage(): void {
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'answer' ] ] ], 'citations' => [] ];
$result = $this->perplexity->parse_response( $data );
$this->assertSame( PRV_Perplexity_Provider::ESTIMATED_COST_PER_PROBE, $result->get_cost_usd() );
}
public function test_openrouter_annotations_path(): void {
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'BPC-157 reconstitution.', 'annotations' => [ [ 'url_citation' => [ 'url' => 'https://peptiderepo.com/bpc-157-reconstitution/' ] ], [ 'url_citation' => [ 'url' => 'https://examine.com/bpc-157' ] ] ] ] ] ], 'usage' => [ 'total_tokens' => 300 ] ];
$result = $this->openrouter->parse_response( $data );
$this->assertTrue( $result->is_cited() );
$this->assertSame( 1, $result->get_our_position() );
}
public function test_openrouter_regex_fallback(): void {
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'See https://peptiderepo.com/tb-500/ and https://examine.com/tb-500 for details.' ] ] ], 'usage' => [ 'total_tokens' => 150 ] ];
$result = $this->openrouter->parse_response( $data );
$this->assertTrue( $result->is_cited() );
}
public function test_openrouter_not_cited(): void {
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'Some response without our domain.' ] ] ] ];
$result = $this->openrouter->parse_response( $data );
$this->assertFalse( $result->is_cited() );
}
public function test_openrouter_cost_from_token_usage(): void {
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'test' ] ] ], 'usage' => [ 'total_tokens' => 1000 ] ];
$result = $this->openrouter->parse_response( $data );
$this->assertSame( 1000 * 0.000002, $result->get_cost_usd() );
}
}