fix(lab): demote E40 to historical evaluation

This commit is contained in:
DCCONSTRUCTIONS
2026-07-30 22:18:46 +03:00
parent e4e5bf6ea1
commit 81d7ad1a77
7 changed files with 65 additions and 34 deletions
@@ -50,6 +50,11 @@ export interface E40CaseCatalog {
access: "read-only"; access: "read-only";
} }
/**
* Immutable v1 storage vocabulary. Product UI interprets these legacy values
* only as support/challenge of the E37 engineering label; neither value
* establishes physical ground truth or authorizes an operational model.
*/
export type E40OperatorVerdict = "confirmed-error" | "rejected-error"; export type E40OperatorVerdict = "confirmed-error" | "rejected-error";
export interface E40OperatorDecision { export interface E40OperatorDecision {
@@ -40,7 +40,10 @@ export function advancedLaboratoryWorkOptions(
{ id: "e37-ravnoves-acceptance", label: "LAB E37 · RAVNOVES00 acceptance R0" }, { id: "e37-ravnoves-acceptance", label: "LAB E37 · RAVNOVES00 acceptance R0" },
{ id: "e38-perception-baseline", label: "LAB E38 · perception quality R1" }, { id: "e38-perception-baseline", label: "LAB E38 · perception quality R1" },
{ id: "e39-perception-refinement", label: "LAB E39 · perception refinement R1" }, { id: "e39-perception-refinement", label: "LAB E39 · perception refinement R1" },
{ id: "e40-perception-product-gate", label: "LAB E40 · leakage-resistant product gate" }, {
id: "e40-perception-product-gate",
label: "LAB E40 · historical visible engineering evaluation",
},
]; ];
return options.filter(({ id }) => available.has(id)); return options.filter(({ id }) => available.has(id));
} }
@@ -112,33 +112,39 @@ function reviewPrompt(
if (item.reference.presence === "object-present") { if (item.reference.presence === "object-present") {
return { return {
question: `${subject} относится к отдельному видимому объекту?`, question: (
`${subject} подтверждает инженерную метку E37 «объект присутствует»?`
),
evidence, evidence,
confirm: ( confirm: (
"Да — объект виден; эталон верен, расхождение E40 подтверждается." "Да — наблюдение поддерживает инженерную метку E37."
), ),
reject: ( reject: (
"Нет — это фон или часть среды; предполагаемая ошибка отклоняется." "Нет — метка E37 оспорена и требует отдельной ревизии."
), ),
}; };
} }
if (item.reference.presence === "background-or-noise") { if (item.reference.presence === "background-or-noise") {
return { return {
question: `${subject} является фоном или шумом, а не объектом?`, question: (
`${subject} подтверждает инженерную метку E37 «фон или шум»?`
),
evidence, evidence,
confirm: ( confirm: (
"Да — это фон или шум; эталон верен, расхождение E40 подтверждается." "Да — наблюдение поддерживает инженерную метку E37."
), ),
reject: ( reject: (
"Нет — отдельный объект есть; предполагаемая ошибка отклоняется." "Нет — метка E37 оспорена и требует отдельной ревизии."
), ),
}; };
} }
return { return {
question: "Проверяемый эталон точнее описывает кадр, чем решение E40?", question: (
"Наблюдение поддерживает инженерную метку E37 для этого расхождения?"
),
evidence, evidence,
confirm: "Да — эталон верен, расхождение E40 подтверждается.", confirm: "Да — наблюдение поддерживает инженерную метку E37.",
reject: "Нет — эталон спорен, предполагаемая ошибка отклоняется.", reject: "Нет — метка E37 оспорена и требует отдельной ревизии.",
}; };
} }
@@ -174,7 +180,7 @@ export function E40CaseReview({ resultId }: { resultId: string }) {
|| nextReview.reviewedItemCount > nextCatalog.total || nextReview.reviewedItemCount > nextCatalog.total
) { ) {
throw new Error( throw new Error(
"Операторская проверка E40 не совпадает с каталогом ошибок.", "Операторская проверка E40 не совпадает с каталогом расхождений.",
); );
} }
setCatalog(nextCatalog); setCatalog(nextCatalog);
@@ -335,7 +341,7 @@ export function E40CaseReview({ resultId }: { resultId: string }) {
) : error || !detail || !selectedCase ? ( ) : error || !detail || !selectedCase ? (
<div className="e40-case-review__state" role="status"> <div className="e40-case-review__state" role="status">
<Icon name="alert" size={18} /> <Icon name="alert" size={18} />
<span>{error ?? "Выберите ошибку для проверки."}</span> <span>{error ?? "Выберите расхождение для проверки."}</span>
</div> </div>
) : ( ) : (
<LaboratoryEvidenceViewer <LaboratoryEvidenceViewer
@@ -352,7 +358,7 @@ export function E40CaseReview({ resultId }: { resultId: string }) {
<div className="e40-case-review__controls"> <div className="e40-case-review__controls">
<div <div
className="e40-case-review__pagination" className="e40-case-review__pagination"
aria-label="Последовательная проверка ошибок" aria-label="Последовательная проверка расхождений"
> >
<IconButton <IconButton
className="e40-case-review__glass-button" className="e40-case-review__glass-button"
@@ -403,7 +409,7 @@ export function E40CaseReview({ resultId }: { resultId: string }) {
overlay={( overlay={(
<aside <aside
className="e40-case-review__telemetry" className="e40-case-review__telemetry"
aria-label="Эталон и результат E40" aria-label="Инженерная метка E37 и результат E40"
> >
<div className="e40-case-review__telemetry-content"> <div className="e40-case-review__telemetry-content">
<span> <span>
@@ -436,7 +442,7 @@ export function E40CaseReview({ resultId }: { resultId: string }) {
<dt>{DIMENSION_LABELS[dimension]}</dt> <dt>{DIMENSION_LABELS[dimension]}</dt>
<dd> <dd>
<span> <span>
Эталон ·{" "} Инженерная метка E37 ·{" "}
{VALUE_LABELS[ {VALUE_LABELS[
stateValue(selectedCase.reference, dimension) stateValue(selectedCase.reference, dimension)
]} ]}
@@ -461,9 +467,9 @@ export function E40CaseReview({ resultId }: { resultId: string }) {
{verdictPending {verdictPending
? "Сохраняем…" ? "Сохраняем…"
: selectedDecision?.verdict === "confirmed-error" : selectedDecision?.verdict === "confirmed-error"
? "Ошибка подтверждена" ? "Метка E37 поддержана"
: selectedDecision?.verdict === "rejected-error" : selectedDecision?.verdict === "rejected-error"
? "Расхождение отклонено" ? "Метка E37 оспорена"
: "Решение оператора"} : "Решение оператора"}
</span> </span>
<div <div
@@ -478,7 +484,7 @@ export function E40CaseReview({ resultId }: { resultId: string }) {
? "true" ? "true"
: undefined : undefined
} }
label={prompt?.confirm ?? "Подтвердить ошибку модели"} label={prompt?.confirm ?? "Поддержать метку E37"}
aria-pressed={ aria-pressed={
selectedDecision?.verdict === "confirmed-error" selectedDecision?.verdict === "confirmed-error"
} }
@@ -495,7 +501,7 @@ export function E40CaseReview({ resultId }: { resultId: string }) {
? "true" ? "true"
: undefined : undefined
} }
label={prompt?.reject ?? "Отклонить ошибку модели"} label={prompt?.reject ?? "Оспорить метку E37"}
aria-pressed={ aria-pressed={
selectedDecision?.verdict === "rejected-error" selectedDecision?.verdict === "rejected-error"
} }
@@ -32,8 +32,8 @@ export function E40Result({
result.developmentCrossValidation.protocols.wholeTrackOrSceneWindow.dimensions result.developmentCrossValidation.protocols.wholeTrackOrSceneWindow.dimensions
); );
const gateLabel = result.qualityGatePassed const gateLabel = result.qualityGatePassed
? "Историческая оценка E40 пройдена" ? "Порог исторического сравнения достигнут"
: "Историческая оценка E40 не пройдена"; : "Порог исторического сравнения не достигнут";
return ( return (
<LaboratoryWorkTemplate <LaboratoryWorkTemplate
summary={( summary={(
@@ -115,40 +115,40 @@ export function E40Result({
result={( result={(
<LaboratoryResultSummary <LaboratoryResultSummary
title={result.qualityGatePassed title={result.qualityGatePassed
? "Source-scoped perception gate RAVNOVES00 закрыт" ? "Историческое сравнение E40 завершено выше заданного порога"
: "Route-coordinate признаки исключены, но product gate ещё не закрыт"} : "Историческое сравнение E40 завершено ниже заданного порога"}
status={gateLabel} status={gateLabel}
statusTone={result.qualityGatePassed ? "success" : "warning"} statusTone={result.qualityGatePassed ? "success" : "warning"}
metrics={[ metrics={[
{ {
label: "Presence", label: "Presence",
value: percent(dimensions.presence.accuracy), value: percent(dimensions.presence.accuracy),
hint: `${formatNumber(dimensions.presence.incorrect, 0)} ошибок · цель 90%`, hint: `${formatNumber(dimensions.presence.incorrect, 0)} расхождений с E37 · порог 90%`,
}, },
{ {
label: "Geometry association", label: "Geometry association",
value: percent(dimensions.geometryAssociation.accuracy), value: percent(dimensions.geometryAssociation.accuracy),
hint: `${formatNumber(dimensions.geometryAssociation.incorrect, 0)} ошибок · цель 90%`, hint: `${formatNumber(dimensions.geometryAssociation.incorrect, 0)} расхождений с E37 · порог 90%`,
}, },
{ {
label: "Freshness", label: "Freshness",
value: percent(dimensions.freshness.accuracy), value: percent(dimensions.freshness.accuracy),
hint: `${formatNumber(dimensions.freshness.incorrect, 0)} ошибок · цель 90%`, hint: `${formatNumber(dimensions.freshness.incorrect, 0)} расхождений с E37 · порог 90%`,
}, },
{ {
label: "High severity", label: "High severity",
value: formatNumber(metrics.highSeverityFailures, 0), value: formatNumber(metrics.highSeverityFailures, 0),
hint: `учёт ${percent(metrics.accountingFraction)} · false free ${formatNumber(metrics.falseFreeClaims, 0)}`, hint: `исторические расхождения · учёт ${percent(metrics.accountingFraction)} · false free ${formatNumber(metrics.falseFreeClaims, 0)}`,
}, },
]} ]}
conclusion={{ conclusion={{
proved: result.qualityGatePassed proved: result.qualityGatePassed
? "На неизменяемом RAVNOVES00 все три task-level dimension достигли 90%, полный denominator учтён, ложное свободное пространство не опубликовано и high-severity ошибок нет." ? "В сравнении с инженерными метками E37 все три task-level dimension достигли 90%, полный denominator учтён, ложное свободное пространство не опубликовано и high-severity расхождений нет."
: `Development-профиль устойчив к двум зависимым разбиениям; historical visible evaluation завершён с полным учётом ${formatNumber(metrics.validationItems, 0)} кейсов и без ложного свободного пространства.`, : `Development-профиль устойчив к двум зависимым разбиениям; historical visible evaluation завершён с полным учётом ${formatNumber(metrics.validationItems, 0)} кейсов и без ложного свободного пространства.`,
notProved: "Не доказаны независимая физическая ground truth, второй маршрут, другой риг, растительная среда, живой rover runtime, навигация, команды или safety.", notProved: "Инженерные метки E37 не являются независимой физической ground truth. Не доказаны второй маршрут, другой риг, растительная среда, operational camera-first runtime, навигация, команды или safety.",
decision: result.qualityGatePassed decision: result.qualityGatePassed
? "Зафиксировать RAVNOVES00 perception gate как закрытый source-scoped этап. Следующий шаг — temporal product state и live-rover replay без расширения полномочий." ? "Сохранить E40 как воспроизводимое историческое сравнение. Не переносить его решения в runtime; следующий кандидат должен отдельно доказать camera-first semantic detection и LiDAR metric geometry."
: `Не принимать source-scoped product gate. Разбирать только оставшиеся sealed ошибки и блокеры (${result.blockingChecks.join(", ")}), не подбирая профиль по validation.`, : `Сохранить E40 только как каталог исторических расхождений и блокеров (${result.blockingChecks.join(", ")}). Не подбирать профиль по visible evaluation и не считать результат product gate.`,
}} }}
/> />
)} )}
@@ -283,7 +283,7 @@ test("E40 reports historical visible evaluation with bounded camera-LiDAR case r
assert.match(e40Source, /Только camera-only использует softmax/); assert.match(e40Source, /Только camera-only использует softmax/);
assert.match(e40Source, /<E40CaseReview resultId=\{result\.resultId\}/); assert.match(e40Source, /<E40CaseReview resultId=\{result\.resultId\}/);
assert.match(e40Source, /historical visible engineering evaluation/); assert.match(e40Source, /historical visible engineering evaluation/);
assert.match(e40Source, /не подбирая профиль по validation/); assert.match(e40Source, /Не подбирать профиль по visible evaluation/);
assert.match(caseReviewSource, /<LaboratoryEvidenceViewer/); assert.match(caseReviewSource, /<LaboratoryEvidenceViewer/);
assert.match(caseReviewSource, /<E30EvidenceProjection/); assert.match(caseReviewSource, /<E30EvidenceProjection/);
assert.match(caseReviewSource, /<E30EvidencePointCloud/); assert.match(caseReviewSource, /<E30EvidencePointCloud/);
@@ -293,14 +293,26 @@ test("E40 reports historical visible evaluation with bounded camera-LiDAR case r
assert.match(caseReviewSource, /Расхождение исторической оценки E40/); assert.match(caseReviewSource, /Расхождение исторической оценки E40/);
assert.match(caseReviewSource, /label="Предыдущее расхождение"/); assert.match(caseReviewSource, /label="Предыдущее расхождение"/);
assert.match(caseReviewSource, /label="Следующее расхождение"/); assert.match(caseReviewSource, /label="Следующее расхождение"/);
assert.match(caseReviewSource, /расхождение E40 подтверждается/); assert.match(caseReviewSource, /наблюдение поддерживает инженерную метку E37/);
assert.match(caseReviewSource, /предполагаемая ошибка отклоняется/); assert.match(caseReviewSource, /метка E37 оспорена/);
assert.match(caseReviewSource, /фиксированная stratum-policy, не вероятность/); assert.match(caseReviewSource, /фиксированная stratum-policy, не вероятность/);
assert.match(e40Source, /не считать результат product gate/);
assert.doesNotMatch(caseReviewSource, /эталон верен/);
assert.doesNotMatch(caseReviewSource, /Ошибка подтверждена/);
assert.doesNotMatch(e40Source, /perception gate RAVNOVES00 закрыт/);
assert.doesNotMatch( assert.doesNotMatch(
e40Source, e40Source,
/className="laboratory-(?:summary|result-summary|result-metrics|result-conclusion)"/, /className="laboratory-(?:summary|result-summary|result-metrics|result-conclusion)"/,
); );
assert.match(advancedSource, /id: "e40-perception-product-gate"/); assert.match(advancedSource, /id: "e40-perception-product-gate"/);
assert.match(
advancedSource,
/LAB E40 · historical visible engineering evaluation/,
);
assert.doesNotMatch(
advancedSource,
/LAB E40 · leakage-resistant product gate/,
);
assert.match(advancedSource, /<E40Result/); assert.match(advancedSource, /<E40Result/);
}); });
@@ -15,6 +15,9 @@ from k1link.artifacts import utc_now_iso, write_json_atomic
E40_OPERATOR_REVIEW_SCHEMA: Final = "missioncore.e40-operator-review/v1" E40_OPERATOR_REVIEW_SCHEMA: Final = "missioncore.e40-operator-review/v1"
E40_OPERATOR_REVIEW_PROTOCOL: Final = "sealed-error-adjudication/v1" E40_OPERATOR_REVIEW_PROTOCOL: Final = "sealed-error-adjudication/v1"
# Frozen v1 storage vocabulary. These values preserve historical hashes used
# by E52; product surfaces must interpret them as support/challenge of the E37
# engineering label, never as independent physical ground truth.
E40OperatorVerdict = Literal["confirmed-error", "rejected-error"] E40OperatorVerdict = Literal["confirmed-error", "rejected-error"]
_RESULT_ID = re.compile(r"^e40-perception-product-gate-[a-f0-9]{64}$") _RESULT_ID = re.compile(r"^e40-perception-product-gate-[a-f0-9]{64}$")
+2
View File
@@ -75,6 +75,8 @@ RootProvider = Callable[[], Path | None]
class E40OperatorVerdictRequest(BaseModel): class E40OperatorVerdictRequest(BaseModel):
"""Legacy v1 storage vocabulary, not an operational truth decision."""
model_config = ConfigDict(extra="forbid") model_config = ConfigDict(extra="forbid")
reviewer_id: str = Field(min_length=1, max_length=128) reviewer_id: str = Field(min_length=1, max_length=128)