feat(lab): canonize versioned report template

This commit is contained in:
DCCONSTRUCTIONS
2026-07-27 16:05:32 +03:00
parent 2c016b117d
commit 95c6540691
20 changed files with 582 additions and 128 deletions
@@ -31,6 +31,28 @@ export interface LaboratoryMethod {
components: readonly LaboratoryMethodComponent[];
}
export interface LaboratoryBrief {
question: string;
approach: string;
principalResult: string;
limitation: string;
}
export interface LaboratoryResultMetric {
label: string;
value: string;
hint: string;
}
export interface LaboratoryResultConclusion {
proved: string;
notProved: string;
decision: string;
}
export const LABORATORY_REPORT_TEMPLATE_VERSION =
"missioncore.laboratory-report/v1";
const EXECUTION_LABELS: Record<LaboratoryExecutionClass, string> = {
deterministic: "Детерминированный",
"ai-inference": "AI inference",
@@ -96,6 +118,7 @@ export function LaboratorySummary({
status,
statusTone = "neutral",
facts,
brief,
method,
}: {
title: string;
@@ -103,6 +126,7 @@ export function LaboratorySummary({
status: string;
statusTone?: "neutral" | "success" | "warning" | "danger" | "accent";
facts: readonly { label: string; value: string }[];
brief: LaboratoryBrief;
method?: LaboratoryMethod | null;
}) {
const methodComplete = method?.completeness === "complete";
@@ -126,6 +150,25 @@ export function LaboratorySummary({
))}
</dl>
<dl className="laboratory-summary__brief">
<div>
<dt>Задача</dt>
<dd>{brief.question}</dd>
</div>
<div>
<dt>Как проверяли</dt>
<dd>{brief.approach}</dd>
</div>
<div>
<dt>Главный результат</dt>
<dd>{brief.principalResult}</dd>
</div>
<div>
<dt>Ограничение</dt>
<dd>{brief.limitation}</dd>
</div>
</dl>
{method ? (
<div className="laboratory-summary__method">
<header>
@@ -193,6 +236,69 @@ export function LaboratoryEvidence({
);
}
export function LaboratoryConclusion({
proved,
notProved,
decision,
}: {
proved: string;
notProved: string;
decision: string;
}) {
return (
<dl className="laboratory-result-conclusion">
<div>
<dt>Доказано</dt>
<dd>{proved}</dd>
</div>
<div>
<dt>Не доказано</dt>
<dd>{notProved}</dd>
</div>
<div>
<dt>Решение</dt>
<dd>{decision}</dd>
</div>
</dl>
);
}
export function LaboratoryResultSummary({
title,
status,
statusTone = "neutral",
metrics,
conclusion,
}: {
title: string;
status: string;
statusTone?: "neutral" | "success" | "warning" | "danger" | "accent";
metrics: readonly LaboratoryResultMetric[];
conclusion: LaboratoryResultConclusion;
}) {
return (
<section className="laboratory-result-summary">
<header>
<div>
<span className="section-eyebrow">РЕЗУЛЬТАТ И ВЫВОД</span>
<h2>{title}</h2>
</div>
<StatusBadge tone={statusTone}>{status}</StatusBadge>
</header>
<div className="laboratory-result-metrics">
{metrics.map((metric) => (
<div key={metric.label}>
<span>{metric.label}</span>
<strong>{metric.value}</strong>
<small>{metric.hint}</small>
</div>
))}
</div>
<LaboratoryConclusion {...conclusion} />
</section>
);
}
export function LaboratoryWorkTemplate({
summary,
evidence,
@@ -205,7 +311,10 @@ export function LaboratoryWorkTemplate({
details?: ReactNode;
}) {
return (
<div className="laboratory-work-template">
<div
className="laboratory-work-template"
data-template-contract={LABORATORY_REPORT_TEMPLATE_VERSION}
>
{summary}
{evidence}
{result}