feat(lab): publish E37 R0 acceptance result
This commit is contained in:
@@ -89,12 +89,56 @@ export interface E33LaboratoryResult {
|
||||
access: "read-only";
|
||||
}
|
||||
|
||||
export interface E37AcceptanceContractResult {
|
||||
resultId: string;
|
||||
createdAtUtc: string | null;
|
||||
sourceSessionId: string;
|
||||
sourceDisplayName: string;
|
||||
status: "accepted-r0-source-scoped-contract";
|
||||
profileId: string;
|
||||
workerNode: string;
|
||||
metrics: {
|
||||
reviewedItems: number;
|
||||
developmentItems: number;
|
||||
validationItems: number;
|
||||
engineeringItems: number;
|
||||
humanExceptionItems: number;
|
||||
terminalOutcomes: number;
|
||||
accountingFraction: number;
|
||||
falseFreeClaims: number;
|
||||
};
|
||||
dimensionDistributions: {
|
||||
presence: Readonly<Record<string, number>>;
|
||||
geometryAssociation: Readonly<Record<string, number>>;
|
||||
freshness: Readonly<Record<string, number>>;
|
||||
};
|
||||
severityDistribution: Readonly<Record<string, number>>;
|
||||
labelProvenance: {
|
||||
engineeringItems: number;
|
||||
humanExceptionItems: number;
|
||||
independentGroundTruth: false;
|
||||
};
|
||||
split: {
|
||||
strategy: string;
|
||||
validationFraction: number;
|
||||
};
|
||||
targets: {
|
||||
presenceTarget: number;
|
||||
geometryAssociationTarget: number;
|
||||
freshnessTarget: number;
|
||||
};
|
||||
qualityTargetEvaluated: false;
|
||||
limitations: readonly string[];
|
||||
access: "read-only";
|
||||
}
|
||||
|
||||
export interface AdvancedLaboratoryResults {
|
||||
e31: E31LaboratoryResult | null;
|
||||
e32: E32LaboratoryResult | null;
|
||||
e33: E33LaboratoryResult | null;
|
||||
e34: E34TemporalLayerResult | null;
|
||||
e35: E35DegradationRecoveryResult | null;
|
||||
e37: E37AcceptanceContractResult | null;
|
||||
}
|
||||
|
||||
export class AdvancedLaboratoryContractError extends Error {
|
||||
@@ -181,6 +225,19 @@ function strings(value: unknown, label: string): readonly string[] {
|
||||
return value.map((item, index) => stringValue(item, `${label}[${index}]`));
|
||||
}
|
||||
|
||||
function numberRecord(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): Readonly<Record<string, number>> {
|
||||
const source = record(value, label);
|
||||
return Object.fromEntries(
|
||||
Object.entries(source).map(([key, item]) => [
|
||||
key,
|
||||
integerValue(item, `${label}.${key}`),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
function contentId(value: unknown, prefix: string, label: string): string {
|
||||
const parsed = stringValue(value, label);
|
||||
if (!new RegExp(`^${prefix}-[a-f0-9]{64}$`).test(parsed)) {
|
||||
@@ -349,6 +406,139 @@ function parseE33(value: unknown): E33LaboratoryResult {
|
||||
};
|
||||
}
|
||||
|
||||
function parseE37(value: unknown): E37AcceptanceContractResult {
|
||||
const item = record(value, "E37");
|
||||
const metrics = record(item.metrics, "E37.metrics");
|
||||
const distributions = record(
|
||||
item.dimension_distributions,
|
||||
"E37.dimension_distributions",
|
||||
);
|
||||
const provenance = record(item.label_provenance, "E37.label_provenance");
|
||||
const split = record(item.split, "E37.split");
|
||||
const targets = record(item.targets, "E37.targets");
|
||||
diagnosticAuthority(item.authority, "E37.authority");
|
||||
if (item.quality_target_evaluated !== false) {
|
||||
throw new AdvancedLaboratoryContractError(
|
||||
"E37.quality_target_evaluated: R0 не должен объявлять метрику проверенной.",
|
||||
);
|
||||
}
|
||||
if (provenance.independent_ground_truth !== false) {
|
||||
throw new AdvancedLaboratoryContractError(
|
||||
"E37.label_provenance: R0 не является независимой разметкой.",
|
||||
);
|
||||
}
|
||||
return {
|
||||
resultId: contentId(
|
||||
item.result_id,
|
||||
"e37-ravnoves-acceptance",
|
||||
"E37.result_id",
|
||||
),
|
||||
createdAtUtc: optionalString(item.created_at_utc, "E37.created_at_utc"),
|
||||
sourceSessionId: stringValue(
|
||||
item.source_session_id,
|
||||
"E37.source_session_id",
|
||||
),
|
||||
sourceDisplayName: stringValue(
|
||||
item.source_display_name,
|
||||
"E37.source_display_name",
|
||||
),
|
||||
status: exactString(
|
||||
item.status,
|
||||
"accepted-r0-source-scoped-contract",
|
||||
"E37.status",
|
||||
),
|
||||
profileId: stringValue(item.profile_id, "E37.profile_id"),
|
||||
workerNode: stringValue(item.worker_node, "E37.worker_node"),
|
||||
metrics: {
|
||||
reviewedItems: integerValue(
|
||||
metrics.reviewed_items,
|
||||
"E37.metrics.reviewed_items",
|
||||
),
|
||||
developmentItems: integerValue(
|
||||
metrics.development_items,
|
||||
"E37.metrics.development_items",
|
||||
),
|
||||
validationItems: integerValue(
|
||||
metrics.validation_items,
|
||||
"E37.metrics.validation_items",
|
||||
),
|
||||
engineeringItems: integerValue(
|
||||
metrics.engineering_items,
|
||||
"E37.metrics.engineering_items",
|
||||
),
|
||||
humanExceptionItems: integerValue(
|
||||
metrics.human_exception_items,
|
||||
"E37.metrics.human_exception_items",
|
||||
),
|
||||
terminalOutcomes: integerValue(
|
||||
metrics.terminal_outcomes,
|
||||
"E37.metrics.terminal_outcomes",
|
||||
),
|
||||
accountingFraction: numberValue(
|
||||
metrics.accounting_fraction,
|
||||
"E37.metrics.accounting_fraction",
|
||||
),
|
||||
falseFreeClaims: integerValue(
|
||||
metrics.false_free_claims,
|
||||
"E37.metrics.false_free_claims",
|
||||
),
|
||||
},
|
||||
dimensionDistributions: {
|
||||
presence: numberRecord(
|
||||
distributions.presence,
|
||||
"E37.dimension_distributions.presence",
|
||||
),
|
||||
geometryAssociation: numberRecord(
|
||||
distributions.geometry_association,
|
||||
"E37.dimension_distributions.geometry_association",
|
||||
),
|
||||
freshness: numberRecord(
|
||||
distributions.freshness,
|
||||
"E37.dimension_distributions.freshness",
|
||||
),
|
||||
},
|
||||
severityDistribution: numberRecord(
|
||||
item.severity_distribution,
|
||||
"E37.severity_distribution",
|
||||
),
|
||||
labelProvenance: {
|
||||
engineeringItems: integerValue(
|
||||
provenance.engineering_items,
|
||||
"E37.label_provenance.engineering_items",
|
||||
),
|
||||
humanExceptionItems: integerValue(
|
||||
provenance.human_exception_items,
|
||||
"E37.label_provenance.human_exception_items",
|
||||
),
|
||||
independentGroundTruth: false,
|
||||
},
|
||||
split: {
|
||||
strategy: stringValue(split.strategy, "E37.split.strategy"),
|
||||
validationFraction: numberValue(
|
||||
split.validation_fraction,
|
||||
"E37.split.validation_fraction",
|
||||
),
|
||||
},
|
||||
targets: {
|
||||
presenceTarget: numberValue(
|
||||
targets.presence_target,
|
||||
"E37.targets.presence_target",
|
||||
),
|
||||
geometryAssociationTarget: numberValue(
|
||||
targets.geometry_association_target,
|
||||
"E37.targets.geometry_association_target",
|
||||
),
|
||||
freshnessTarget: numberValue(
|
||||
targets.freshness_target,
|
||||
"E37.targets.freshness_target",
|
||||
),
|
||||
},
|
||||
qualityTargetEvaluated: false,
|
||||
limitations: strings(item.limitations, "E37.limitations"),
|
||||
access: exactString(item.access, "read-only", "E37.access"),
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchOne<T>(
|
||||
path: string,
|
||||
parser: (value: unknown) => T,
|
||||
@@ -373,14 +563,15 @@ export async function fetchAdvancedLaboratoryResults({
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
} = {}): Promise<AdvancedLaboratoryResults> {
|
||||
const [e31, e32, e33, e34, e35] = await Promise.all([
|
||||
const [e31, e32, e33, e34, e35, e37] = await Promise.all([
|
||||
fetchOne("/api/v1/laboratory/e31/results?limit=1", parseE31, fetcher, signal),
|
||||
fetchOne("/api/v1/laboratory/e32/results?limit=1", parseE32, fetcher, signal),
|
||||
fetchOne("/api/v1/laboratory/e33/results?limit=1", parseE33, fetcher, signal),
|
||||
fetchE34TemporalLayerResult({ fetcher, signal }),
|
||||
fetchE35DegradationRecoveryResult({ fetcher, signal }),
|
||||
fetchOne("/api/v1/laboratory/e37/results?limit=1", parseE37, fetcher, signal),
|
||||
]);
|
||||
return { e31, e32, e33, e34, e35 };
|
||||
return { e31, e32, e33, e34, e35, e37 };
|
||||
}
|
||||
import {
|
||||
fetchE34TemporalLayerResult,
|
||||
|
||||
@@ -9,6 +9,7 @@ import { E32Result } from "./E32Result";
|
||||
import { E33Result } from "./E33Result";
|
||||
import { E34Result } from "./E34Result";
|
||||
import { E35Result } from "./E35Result";
|
||||
import { E37Result } from "./E37Result";
|
||||
import { RecordedReplayEvidence } from "./RecordedReplayEvidence";
|
||||
|
||||
export type AdvancedLaboratoryWorkId =
|
||||
@@ -16,7 +17,8 @@ export type AdvancedLaboratoryWorkId =
|
||||
| "e32-track-geometry"
|
||||
| "e33-worker-shadow"
|
||||
| "e34-temporal-layer"
|
||||
| "e35-degradation-recovery";
|
||||
| "e35-degradation-recovery"
|
||||
| "e37-ravnoves-acceptance";
|
||||
|
||||
type LaboratoryWorkspaceProps = WorkspaceRendererProps & {
|
||||
SpatialView: ComponentType<WorkspaceRendererProps>;
|
||||
@@ -31,6 +33,7 @@ export function isAdvancedLaboratoryWorkId(
|
||||
|| value === "e33-worker-shadow"
|
||||
|| value === "e34-temporal-layer"
|
||||
|| value === "e35-degradation-recovery"
|
||||
|| value === "e37-ravnoves-acceptance"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,6 +72,12 @@ export function advancedLaboratoryWorkOptions(
|
||||
label: "LAB E35 · degradation recovery",
|
||||
});
|
||||
}
|
||||
if (results.e37) {
|
||||
options.push({
|
||||
id: "e37-ravnoves-acceptance",
|
||||
label: "LAB E37 · RAVNOVES00 acceptance R0",
|
||||
});
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -106,6 +115,9 @@ export function AdvancedLaboratoryResult({
|
||||
failedSessionId: string | null;
|
||||
replayError: string | null;
|
||||
}) {
|
||||
if (workId === "e37-ravnoves-acceptance" && results.e37) {
|
||||
return <E37Result rigLabel={rigLabel} result={results.e37} />;
|
||||
}
|
||||
if (workId === "e35-degradation-recovery" && results.e35) {
|
||||
return <E35Result rigLabel={rigLabel} result={results.e35} />;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
import {
|
||||
LaboratoryEvidence,
|
||||
LaboratoryResultSummary,
|
||||
LaboratorySummary,
|
||||
LaboratoryWorkTemplate,
|
||||
} from "../../components/laboratory/LaboratoryPresentation";
|
||||
import type { E37AcceptanceContractResult } from "../../core/laboratory/advancedResults";
|
||||
import { formatNumber } from "../../presentation";
|
||||
|
||||
function distribution(
|
||||
values: Readonly<Record<string, number>>,
|
||||
): string {
|
||||
return Object.entries(values)
|
||||
.sort((left, right) => right[1] - left[1])
|
||||
.map(([label, count]) => `${label}: ${formatNumber(count, 0)}`)
|
||||
.join(" · ");
|
||||
}
|
||||
|
||||
function ContractEvidence({
|
||||
result,
|
||||
}: {
|
||||
result: E37AcceptanceContractResult;
|
||||
}) {
|
||||
return (
|
||||
<div className="laboratory-result-metrics">
|
||||
<div>
|
||||
<span>Presence</span>
|
||||
<strong>{Object.keys(result.dimensionDistributions.presence).length} исхода</strong>
|
||||
<small>{distribution(result.dimensionDistributions.presence)}</small>
|
||||
</div>
|
||||
<div>
|
||||
<span>Geometry association</span>
|
||||
<strong>
|
||||
{Object.keys(result.dimensionDistributions.geometryAssociation).length}
|
||||
{" исходов"}
|
||||
</strong>
|
||||
<small>{distribution(result.dimensionDistributions.geometryAssociation)}</small>
|
||||
</div>
|
||||
<div>
|
||||
<span>Freshness</span>
|
||||
<strong>{Object.keys(result.dimensionDistributions.freshness).length} исхода</strong>
|
||||
<small>{distribution(result.dimensionDistributions.freshness)}</small>
|
||||
</div>
|
||||
<div>
|
||||
<span>Критичность</span>
|
||||
<strong>{Object.keys(result.severityDistribution).length} уровня</strong>
|
||||
<small>{distribution(result.severityDistribution)}</small>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function E37Result({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: E37AcceptanceContractResult;
|
||||
}) {
|
||||
const metrics = result.metrics;
|
||||
const percent = (value: number) => (
|
||||
`${(value * 100).toLocaleString("ru-RU", { maximumFractionDigits: 1 })}%`
|
||||
);
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="LAB E37 · контракт приёмки RAVNOVES00 R0"
|
||||
description="Зафиксированы неизменяемый набор проверенных кейсов, отдельный validation holdout и три независимые метрики, по которым дальше будет измеряться качество сенсорного контура. Эта работа определяет честные правила измерения, но ещё не объявляет достижение 90%."
|
||||
status="R0-контракт принят"
|
||||
statusTone="success"
|
||||
facts={[
|
||||
{
|
||||
label: "Конфигурация",
|
||||
value: `${rigLabel} · RAVNOVES00`,
|
||||
},
|
||||
{
|
||||
label: "Проверено",
|
||||
value: `${formatNumber(metrics.reviewedItems, 0)} / ${formatNumber(metrics.terminalOutcomes, 0)}`,
|
||||
},
|
||||
{
|
||||
label: "Holdout",
|
||||
value: `${formatNumber(metrics.validationItems, 0)} validation`,
|
||||
},
|
||||
{
|
||||
label: "Исполнение",
|
||||
value: `Worker 006 · ${result.workerNode}`,
|
||||
},
|
||||
]}
|
||||
brief={{
|
||||
question: "На каком неизменяемом наборе и по каким отдельным критериям честно измерять приближение сенсорного контура к 90% на RAVNOVES00?",
|
||||
approach: "Все 486 кейсов E30 сведены в одну онтологию presence, geometry association и freshness. Внутри каждого source stratum и диапазона детерминированно заморожен 30-процентный validation holdout; два спорных кейса заменены сохранёнными решениями пользователя.",
|
||||
principalResult: `Учтены все ${formatNumber(metrics.reviewedItems, 0)} кейсов: ${formatNumber(metrics.developmentItems, 0)} development и ${formatNumber(metrics.validationItems, 0)} validation. Потерь учёта и false-free claims нет.`,
|
||||
limitation: "Разметка инженерная и source-scoped, а не независимый ground truth. Точность presence, geometry и freshness в этой работе не вычислялась.",
|
||||
}}
|
||||
method={{
|
||||
completeness: "complete",
|
||||
executionClass: "deterministic",
|
||||
pipelineId: result.profileId,
|
||||
components: [
|
||||
{
|
||||
kind: "source",
|
||||
name: result.sourceDisplayName,
|
||||
version: `${formatNumber(metrics.reviewedItems, 0)} reviewed E30 items`,
|
||||
role: "неизменяемое camera + LiDAR evidence",
|
||||
identitySha256: null,
|
||||
},
|
||||
{
|
||||
kind: "algorithm",
|
||||
name: "Stratified deterministic holdout",
|
||||
version: `${percent(result.split.validationFraction)} validation`,
|
||||
role: "source-stratum и range-balanced split без ручной перетасовки",
|
||||
identitySha256: null,
|
||||
},
|
||||
{
|
||||
kind: "runtime",
|
||||
name: "Worker 006",
|
||||
version: result.workerNode,
|
||||
role: "изолированная offline-сборка контракта без командных полномочий",
|
||||
identitySha256: null,
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="ЗАМОРОЖЕННЫЙ КОНТРАКТ"
|
||||
title="Онтология, распределение меток и критичность"
|
||||
kind="diagnostic-model"
|
||||
>
|
||||
<ContractEvidence result={result} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Измерительная база R0 заморожена; quality gate переносится в R1"
|
||||
status="R0 принят"
|
||||
statusTone="success"
|
||||
metrics={[
|
||||
{
|
||||
label: "Полный учёт",
|
||||
value: percent(metrics.accountingFraction),
|
||||
hint: `${formatNumber(metrics.terminalOutcomes, 0)} terminal outcomes`,
|
||||
},
|
||||
{
|
||||
label: "Development / validation",
|
||||
value: `${formatNumber(metrics.developmentItems, 0)} / ${formatNumber(metrics.validationItems, 0)}`,
|
||||
hint: `${percent(result.split.validationFraction)} holdout`,
|
||||
},
|
||||
{
|
||||
label: "Human exceptions",
|
||||
value: formatNumber(metrics.humanExceptionItems, 0),
|
||||
hint: `${formatNumber(metrics.engineeringItems, 0)} engineering-reviewed`,
|
||||
},
|
||||
{
|
||||
label: "False-free claims",
|
||||
value: formatNumber(metrics.falseFreeClaims, 0),
|
||||
hint: "отсутствие точек не считается свободным пространством",
|
||||
},
|
||||
]}
|
||||
conclusion={{
|
||||
proved: "Для RAVNOVES00 зафиксированы воспроизводимый denominator, неизменяемый validation holdout, раздельные метрики presence, geometry association и freshness, полная provenance и 100-процентный terminal accounting.",
|
||||
notProved: "Не доказаны 90-процентная точность ни по одной метрике, независимый ground truth, перенос на другой маршрут или риг, а также пригодность для навигации и safety.",
|
||||
decision: "Принять R0 как единственную измерительную базу RAVNOVES00. Следующая плановая работа R1 должна вычислить baseline на замороженном validation и улучшать development без изменения holdout.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -68,6 +68,7 @@ const EMPTY_ADVANCED_RESULTS: AdvancedLaboratoryResults = {
|
||||
e33: null,
|
||||
e34: null,
|
||||
e35: null,
|
||||
e37: null,
|
||||
};
|
||||
|
||||
function digestFromContentId(value: string | null | undefined): string | null {
|
||||
|
||||
Reference in New Issue
Block a user