79 lines
5.2 KiB
PHP
79 lines
5.2 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||
require __DIR__ . '/fixtures/CompleteTcmCase.php';
|
||
|
||
use app\adminapi\service\AiRequiredSource;
|
||
use app\adminapi\service\TcmClinicalEvidenceIndex as Index;
|
||
use app\adminapi\service\TcmClinicalEvidenceContract as Evidence;
|
||
use app\adminapi\service\TcmClinicalFactStateGuard as Facts;
|
||
use app\adminapi\service\TcmClinicalReportStream as Stream;
|
||
use app\adminapi\service\TcmHerbalPremiseGuard as Premise;
|
||
use app\adminapi\service\TcmLongReportContract as Shape;
|
||
|
||
$checks = 0;
|
||
function postfixExpect(bool $ok, string $why): void { ++$GLOBALS['checks']; if (!$ok) throw new RuntimeException($why); }
|
||
$snapshot = (new ReflectionMethod(\app\adminapi\logic\tcm\PatientAiReportLogic::class, 'buildSourceSnapshotFromRows'))
|
||
->invoke(null, CompleteTcmCase::rows());
|
||
$submission = (new ReflectionMethod(\app\adminapi\logic\tcm\PatientAiReportLogic::class, 'sanitizeSnapshotForUpstream'))
|
||
->invoke(null, AiRequiredSource::submission($snapshot));
|
||
$ledger = Facts::build(CompleteTcmCase::current(), $submission);
|
||
$index = Index::build($ledger);
|
||
$baseline = '';
|
||
foreach ($ledger['sources'] as $source) if ($source['field'] === 'current_medications' && $source['scope'] === 'current') {
|
||
$baseline = '既有用药基线:“' . $source['quote'] . '”(' . $source['id'] . ')。'; break;
|
||
}
|
||
postfixExpect($baseline !== '', 'The ongoing-prescription control uses its actual original source ID and exact quote.');
|
||
postfixExpect(($ledger['sources']['s30']['quote'] ?? '') === '藿香正气散(旧记录、早已停用)',
|
||
'The exact immutable fixture projection retains the audited historical s30 bytes.');
|
||
$query = '<USER_QUESTION>生成1800至2200字完整中医辨证长报告。</USER_QUESTION>';
|
||
$prefix = "一、四诊\n\n";
|
||
foreach (Index::ROLES as $label => $role) {
|
||
$span = null; $source = null;
|
||
foreach ($index['sources'] as $candidate) {
|
||
if ($candidate['scope'] !== 'current') continue;
|
||
foreach ($candidate['spans'] as $part) if ($part['role'] === $role && ($part['recorded'] ?? true)) {
|
||
$span = $part; $source = $candidate; break 2;
|
||
}
|
||
}
|
||
$prefix .= $label . ':' . ($span !== null
|
||
? $source['date'] . '“' . $span['quote'] . '”(' . $source['id'] . ')。'
|
||
: ($role === 'palpation' ? '其他触诊未记录,脉象见独立脉象项。' : '未记录。')) . "\n\n";
|
||
}
|
||
$engineering = '本段为离线字节交付测试,检验来源与输出边界,工程文字不构成诊断或用药依据。';
|
||
foreach (['二、八纲', '三、气血津液与脏腑', '四、证名', '五、治法'] as $title) $prefix .= $title . "\n\n" . str_repeat($engineering, 3) . "\n\n";
|
||
$wire = static function (string $snippet) use ($prefix, $engineering): string {
|
||
$out = $prefix . "六、中药方药及复核监测\n\n" . $snippet . "\n\n" . str_repeat($engineering, 3);
|
||
return $out . str_repeat('核', 2000 - mb_strlen($out, 'UTF-8'));
|
||
};
|
||
foreach ([
|
||
'主方方向:“甲乙散”(s1)。核心方证证据不足。',
|
||
'历史记录:“藿香正气散”(s30),本次建议沿用。核心方证证据不足。',
|
||
'历史记录:“藿香正气散”(s30)。本次建议沿用该方。核心方证证据不足。',
|
||
'历史记录:“藿香正气散”(s30)。本次建议沿用旧方。核心方证证据不足。',
|
||
] as $snippet) {
|
||
$draft = $wire($snippet);
|
||
postfixExpect(Shape::validate($draft, $query)['valid'] && Facts::validate($ledger, $draft)['valid']
|
||
&& Evidence::validate($index, $draft, true)['valid'],
|
||
'The exact source/protocol/shape-valid counterexample is independently visible to the premise checkpoint.');
|
||
$visible = '';
|
||
$stream = new Stream($ledger, static function ($s) use (&$visible): bool { $visible .= $s; return true; }, null, '', null, $index, $query);
|
||
postfixExpect(!$stream->push($draft) && !$stream->finish() && $visible === $prefix
|
||
&& in_array('HERBAL_PREMISE_SELF_CONFLICT', array_column($stream->issues(), 'code'), true),
|
||
'Actual production Stream keeps the entire contradicted sixth section private.');
|
||
}
|
||
$earlyPrefix = substr($prefix, 0, strpos($prefix, '三、'));
|
||
$visible = ''; $stream = new Stream($ledger, static function ($s) use (&$visible): bool { $visible .= $s; return true; }, null, '', null, $index, $query);
|
||
postfixExpect($stream->push($earlyPrefix) && !$stream->finish() && $visible === $earlyPrefix
|
||
&& !in_array('REPORT_FINAL_SECTION_UNDELIVERED', array_column($stream->issues(), 'code'), true),
|
||
'The prior [1,2] early-truncation marker fix remains intact on the actual fixture.');
|
||
foreach ([
|
||
'历史记录:“藿香正气散”(s30),仅作历史。',
|
||
'历史记录:“藿香正气散”(s30),本次不沿用。',
|
||
'历史记录:“藿香正气散”(s30)。本次不建议使用该方。',
|
||
'历史记录:“藿香正气散”(s30)。本次建议不使用该方。',
|
||
$baseline,
|
||
] as $control) postfixExpect(Premise::validate($control . '核心方证证据不足。', $ledger)['valid'],
|
||
'Actual-source historical/non-use/current-baseline controls do not become new prescriptions: ' . $control);
|
||
echo "TCM postfix premise scope: {$checks} assertions passed (actual immutable sources; offline engineering wire only).\n";
|