61 lines
4.3 KiB
PHP
61 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
// Pure policy normalization and presentation checks: no App initialize, .env, database or network.
|
|
require dirname(__DIR__) . '/vendor/autoload.php';
|
|
|
|
use app\common\service\prescriptionai\PrescriptionAiVisibility as Visibility;
|
|
|
|
$checks = 0;
|
|
$expect = static function (bool $condition, string $message) use (&$checks): void {
|
|
if (!$condition) { throw new RuntimeException($message); }
|
|
$checks++;
|
|
};
|
|
$expect(Visibility::normalizePolicy(['role_ids' => ['7', 2, 7], 'admin_ids' => ['9', 3]])
|
|
=== ['role_ids' => [2, 7], 'admin_ids' => [3, 9]], 'IDs normalize, deduplicate and sort');
|
|
$expect(Visibility::normalizePolicy(['role_ids' => [], 'admin_ids' => []])
|
|
=== ['role_ids' => [], 'admin_ids' => []], 'empty policy stays empty');
|
|
foreach ([[], ['role_ids' => []], ['role_ids' => [], 'admin_ids' => [], 'root' => true],
|
|
['role_ids' => '*', 'admin_ids' => []], ['role_ids' => [true], 'admin_ids' => []],
|
|
['role_ids' => [1.0], 'admin_ids' => []], ['role_ids' => [-1], 'admin_ids' => []],
|
|
['role_ids' => ['01'], 'admin_ids' => []], ['role_ids' => ['1,2'], 'admin_ids' => []],
|
|
['role_ids' => ['id' => 1], 'admin_ids' => []], ['role_ids' => [PHP_INT_MAX], 'admin_ids' => []],
|
|
['role_ids' => array_fill(0, Visibility::MAX_ROLES + 1, 1), 'admin_ids' => []]] as $invalid) {
|
|
try { Visibility::normalizePolicy($invalid); $expect(false, 'invalid policy must fail'); }
|
|
catch (DomainException $e) { $checks++; }
|
|
}
|
|
|
|
$sentinel = 'private-agreement-sentinel';
|
|
$body = ['report' => ['summary' => 'clinical report', 'comparison' => ['reason' => $sentinel], 'raw' => [$sentinel],
|
|
'unknown_debug' => ['normalization' => $sentinel]],
|
|
'candidate' => ['status' => 'available_for_review', 'reason' => 'clinical reasoning', 'herbs' => [['name' => '测试药材']]],
|
|
'comparison' => ['score' => 88, 'normalization' => ['matched_contribution_sum' => 2]],
|
|
'coverage' => ['status' => 'complete'], 'usage' => ['total_calls' => 2],
|
|
'knowledge_source' => ['title' => 'clinical reference'], 'ancient_book_sources' => [['title' => 'book']],
|
|
'score' => $sentinel, 'result' => [$sentinel], 'raw' => [$sentinel], 'body' => [$sentinel],
|
|
'progress' => ['stage' => 'poisoned']];
|
|
$public = Visibility::reportBody($body, false);
|
|
$expect(!str_contains(json_encode($public), $sentinel) && !isset($public['comparison']), 'comparison and unknown raw body paths cannot escape');
|
|
$expect($public['report']['summary'] === 'clinical report' && $public['candidate']['reason'] === 'clinical reasoning'
|
|
&& $public['coverage']['status'] === 'complete', 'report, candidate reasoning and coverage survive');
|
|
$private = Visibility::reportBody($body, true);
|
|
$expect($private['comparison']['score'] === 88 && !isset($private['result']) && !isset($private['progress']),
|
|
'authorized comparison survives but arbitrary body cannot override response fields');
|
|
$expect(!isset($private['report']['unknown_debug']) && !isset($private['report']['raw']),
|
|
'known clinical report fields are projected at every depth for all viewers');
|
|
$batch = ['comparison_type' => $sentinel, 'baseline_eligible' => true, 'baseline_exclusion_reasons' => [$sentinel],
|
|
'models' => ['qwen' => ['status' => 'success', 'score' => 88, 'herb_score' => 90,
|
|
'reason' => $sentinel, 'comparison_status' => 'comparable', 'comparison_reason_code' => $sentinel,
|
|
'algorithm_version' => $sentinel, 'dictionary_version' => $sentinel, 'error_code' => '',
|
|
'comparison' => ['rows' => [$sentinel]], 'progress' => ['stage' => 'completed']] + $public,
|
|
'openai' => ['status' => 'failed', 'error_code' => 'UPSTREAM_TIMEOUT', 'reason' => '模型请求超时']]];
|
|
$hidden = Visibility::projectBatch($batch, false);
|
|
$expect($hidden['agreement_visible'] === false && !str_contains(json_encode($hidden), $sentinel), 'whole batch removes all metric aliases and derived fields');
|
|
$expect($hidden['models']['openai']['reason'] === '模型请求超时'
|
|
&& $hidden['models']['qwen']['progress']['stage'] === 'completed', 'failure explanation and trusted progress remain');
|
|
$expect(Visibility::projectBatch($batch, true)['models']['qwen']['score'] === 88, 'authorized stored metric is unchanged');
|
|
$expect(Visibility::projectBatch(['models' => []], false) === ['models' => [], 'agreement_visible' => false], 'empty batch advertises capability');
|
|
|
|
echo "Prescription AI visibility: {$checks} offline checks passed\n";
|