Files
zyt/server/tests/TcmHerbalPostfixScopeTest.php
2026-10-27 14:03:35 +08:00

79 lines
5.2 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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";