fix(lab): demote E40 to historical evaluation
This commit is contained in:
@@ -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}$")
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user