$match[1] . <<<'PHP' foreach ($ledger['sources'] as $source) { if ($source['quote'] === $quote && $source['field'] === $field && $source['scope'] === $scope && $source['date'] === $date) return; } PHP, $implementation, 1, $lookupReplacements ); ledgerExpect($lookupReplacements === 1 && is_string($reference), 'Original lookup reference is restored exactly once'); $reference = str_replace('final class TcmClinicalFactStateGuard', 'final class LegacyClinicalFactStateLedgerReference', $reference, $classReplacements); ledgerExpect($classReplacements === 1, 'Reference class is isolated from the real guard'); eval(substr($reference, strlen(' 51, 'diagnosis_date' => $date . ' 09:45:00', 'chief_complaint' => '被明确别名覆盖的原始值', 'chief_complaint_text' => '口干', 'present_illness' => '活动后气短,无胸痛;未记录固定刺痛或耳鸣。', 'present_illness_text' => '', 'allergy_history' => '否认药物过敏史', 'allergy_history_text' => '未记录', 'family_history' => '否认', 'surgery_history' => null, 'trauma_history' => '否认', 'trauma_history_text' => '', 'pregnancy_history' => 0, 'tongue' => '舌淡红,苔少;无黄腻苔、紫暗或瘀斑。', 'pulse' => '脉细弱,按之无力;不浮、不滑。', 'current_medications' => '本次用药未记录;既往服用合成药,早已停用。', 'remark' => '联系 13900000001 a@example.test https://example.test/a', ]; $sharedNote = ['diagnosis_id' => 51, 'note_date' => $date, 'content' => '否认腹痛;未记录耳鸣。']; $submission = ['required_content' => [ ['key' => 'chief_complaint', 'value' => [ ['id' => 51, 'diagnosis_date' => $date, 'chief_complaint' => '口干', 'chief_complaint_text' => ' 口干 '], ['id' => 51, 'diagnosis_date' => '2026-10-22', 'chief_complaint' => '口干'], ['id' => 50, 'diagnosis_date' => $date, 'chief_complaint' => '口干'], ['diagnosis_date' => $date, 'chief_complaint' => '口干'], ['chief_complaint' => '口干'], ['id' => 51, 'diagnosis_date' => $date, 'complaint' => '口干'], ['id' => 51, 'diagnosis_date' => $date, 'chief_complaint' => '口干。', 'chief_complaint_text' => '手麻未记录'], ]], ['key' => 'present_illness', 'value' => [ ['diagnosis_id' => 51, 'diagnosis_date' => $date, 'present_illness' => $diagnosis['present_illness'], 'present_illness_text' => $diagnosis['present_illness']], ['id' => 50, 'diagnosis_date' => '2020-01-01', 'present_illness' => '既往有胸痛;否认气短。'], ]], ['key' => 'other_history', 'value' => [ ['id' => 51, 'diagnosis_date' => $date, 'allergy_history_text' => '未记录', 'family_history' => '否认', 'surgery_history' => '无', 'trauma_history' => null, 'pregnancy_history' => false], ]], ['key' => 'diagnosis_info', 'value' => [ ['id' => 51, 'diagnosis_date' => $date, 'tongue' => $diagnosis['tongue'], 'tongue_text' => $diagnosis['tongue'], 'pulse' => $diagnosis['pulse'], 'pulse_condition' => $diagnosis['pulse']], ['id' => 50, 'diagnosis_date' => '2020-01-01', 'tongue' => '舌红绛,苔黄腻。', 'pulse' => '脉弦滑有力。'], ]], ['key' => 'doctor_image_notes', 'value' => [$sharedNote, $sharedNote, ['diagnosis_id' => 51, 'note_date' => $date, 'text' => $sharedNote['content']]]], ['key' => 'doctor_file_notes', 'value' => [$sharedNote, ['id' => 51, 'record_date' => $date, 'remark' => '联系 13900000002 b@example.test https://example.test/b']]], ['key' => 'daily_tracking', 'value' => [ ['diagnosis_id' => 51, 'record_date' => $date, 'content' => $sharedNote['content']], ['record_date' => $date, 'note' => '未记录'], ]], ['key' => 'prescriptions', 'value' => [ ['diagnosis_id' => 51, 'prescription_date' => $date, 'prescription_name' => '合成历史方', 'usage_instruction' => '既往服用,非本次建议。'], ]], ['key' => 'video_consultation_text', 'value' => [ ['diagnosis_id' => 51, 'end_time' => $date . ' 10:00:00', 'transcript_text' => '当前口干;上次否认胸痛。', 'segments' => [['text' => '当前口干;上次否认胸痛。']]], ]], ['key' => 'chat', 'value' => [ ['diagnosis_id' => 51, 'msg_time' => $date, 'text' => '口干', 'parts' => [['text' => '口干']]], ['msg_time' => $date, 'text' => ' 0 '], ['msg_time' => $date, 'text' => '00'], ['msg_time' => $date, 'text' => '01'], ['msg_time' => $date, 'text' => '1'], ['msg_time' => $date, 'text' => 'none'], ['msg_time' => $date, 'text' => 'NONE'], ['msg_time' => $date, 'text' => "值\0text|s:7:\"current\";a:1:{i:0;s:1:\"x\";}"], ['msg_time' => $date, 'text' => "值\0text|s:7:\"current\";a:1:{i:0;s:1:\"y\";}"], ['msg_time' => $date, 'text' => "\xC3\x28"], ['msg_time' => $date, 'text' => "\xC3\x29"], ['msg_time' => $date, 'text' => ''], ['msg_time' => $date, 'text' => ' '], ['msg_time' => $date, 'text' => null], ['msg_time' => $date, 'text' => 0], ['msg_time' => $date, 'text' => false], ]], ['key' => 'unsupported', 'value' => [['text' => '不支持的类别不得进入账本']]], ['key' => 'chat', 'value' => '非数组类别值'], null, ]]; function ledgerEquivalent(array $diagnosis, array $submission, string $label): array { $actual = Guard::build($diagnosis, $submission); $expected = Reference::build($diagnosis, $submission); ledgerExpect($actual === $expected, $label . ': complete ledger retains every key, type, value and insertion order'); ledgerExpect(serialize($actual) === serialize($expected), $label . ': complete serialized ledger is byte-identical'); ledgerExpect(Guard::prompt($actual) === Reference::prompt($expected), $label . ': prompt bytes are unchanged'); ledgerExpect(array_keys($actual) === ['version', 'sources', 'assertions', 'exam_features', 'field_states'], $label . ': private membership index is absent from public ledger'); return $actual; } $ledger = ledgerEquivalent($diagnosis, $submission, 'Mixed duplicate and longitudinal fixture'); $sources = $ledger['sources']; ledgerExpect($sources['s1'] === ['id' => 's1', 'path' => 'current.chief_complaint', 'field' => 'chief_complaint', 'scope' => 'current', 'date' => $date, 'quote' => '口干'], 'First source ID, original path and exact tuple are preserved'); $dryMouth = array_values(array_filter($sources, static fn (array $source): bool => $source['quote'] === '口干')); ledgerExpect(array_map(static fn (array $source): array => [$source['field'], $source['scope'], $source['date']], $dryMouth) === [['chief_complaint', 'current', $date], ['chief_complaint', 'current', '2026-10-22'], ['chief_complaint', 'historical', $date], ['chief_complaint', 'unspecified', $date], ['chief_complaint', 'unspecified', ''], ['complaint', 'current', $date], ['text', 'historical', $date], ['text', 'historical', '']], 'Same quote retains distinct field/date/current/historical/unspecified tuples, including undated nested parts'); ledgerExpect(count(array_filter($sources, static fn (array $source): bool => $source['quote'] === $GLOBALS['sharedNote']['content'])) === 3, 'Duplicate across projections keeps first path but distinct field/scope remains'); $firstNote = array_values(array_filter($sources, static fn (array $source): bool => $source['quote'] === $GLOBALS['sharedNote']['content'])); ledgerExpect($firstNote[0]['path'] === 'doctor_image_notes.0.content', 'Later equal tuple never overwrites original path'); ledgerExpect(count(array_filter($sources, static fn (array $source): bool => $source['field'] === 'remark')) === 1, 'Membership is calculated after identical existing redaction'); ledgerExpect(count(array_filter($sources, static fn (array $source): bool => $source['quote'] === '')) === 1, 'Malformed UTF-8 retains original post-redaction empty-source behavior'); foreach (['unknown', 'positive', 'negative'] as $state) { ledgerExpect(in_array($state, array_column($ledger['assertions'], 'state'), true), 'Fixture exercises ' . $state . ' assertions'); } $reports = [ '口干;无胸痛。', '固定刺痛或耳鸣未记录。', '无固定刺痛。', '患者有固定刺痛。', '舌淡红,苔少;无黄腻苔、紫暗或瘀斑。', '舌红绛,苔黄腻。', '脉细弱,按之无力;不浮、不滑。', '脉弦滑有力。', '过敏史:未记录。', '过敏史:无。', '家族史:无。', '既往有胸痛;否认气短。', '当前无气短。', '本次用药未记录。', '当前正在服用合成药。', '若出现固定刺痛,应重新评估。', '【来源:s1】口干。', '【来源:s999999】口干。', "\xC3\x28", '', ]; $referenceLedger = Reference::build($diagnosis, $submission); $validResults = []; foreach ($reports as $report) { $actual = Guard::validate($ledger, $report); $expected = Reference::validate($referenceLedger, $report); ledgerExpect(serialize($actual) === serialize($expected), 'Every validation issue, source ID and order remains byte-identical'); $validResults[$actual['valid'] ? 'valid' : 'invalid'] = true; } ledgerExpect(count($validResults) === 2, 'Validation comparison exercises both passing and rejected reports'); ledgerEquivalent([], [], 'Empty build after populated build'); ledgerExpect(Guard::build($diagnosis, $submission) === $ledger, 'Repeated build has no cross-request membership state'); function uniqueHistory(int $count): array { $rows = []; for ($i = 0; $i < $count; ++$i) $rows[] = ['msg_time' => '2020-01-01', 'text' => 'synthetic-history-source-' . $i]; return ['required_content' => [['key' => 'chat', 'value' => $rows]]]; } $medium = uniqueHistory(2000); $mediumLedger = ledgerEquivalent([], $medium, '2,000 unique historical sources'); ledgerExpect(count($mediumLedger['sources']) === 2000 && count($mediumLedger['assertions']) === 2000, 'Large equivalence fixture preserves all source and assertion entries'); unset($mediumLedger); // Eightfold growth should remain broadly linear. Median runs and a generous // relative bound tolerate shared-host noise without imposing an absolute limit. Guard::build([], uniqueHistory(100)); $timings = []; foreach ([2000, 16000] as $count) { $history = $count === 2000 ? $medium : uniqueHistory($count); $elapsed = []; for ($run = 0; $run < 3; ++$run) { $start = hrtime(true); $largeLedger = Guard::build([], $history); $elapsed[] = (hrtime(true) - $start) / 1000000; ledgerExpect(count($largeLedger['sources']) === $count && count($largeLedger['assertions']) === $count, 'Scaling fixture preserves every unique source and assertion'); $tail = $largeLedger['sources']['s' . $count]; ledgerExpect($tail['path'] === 'chat.' . ($count - 1) . '.text' && $tail['quote'] === 'synthetic-history-source-' . ($count - 1) && $tail['scope'] === 'historical' && $tail['date'] === '2020-01-01', 'Scaling fixture retains original tail path, quote, scope and date'); unset($largeLedger); } sort($elapsed); $timings[$count] = $elapsed[1]; } ledgerExpect($timings[16000] < $timings[2000] * 24 + 50, 'Eightfold history growth avoids original quadratic lookup scaling: ' . json_encode($timings)); echo 'Clinical fact ledger equivalence/scaling: ' . $checks . ' assertions passed (pure, no network/database). ' . 'Median ms: ' . json_encode($timings) . "\n";