fix(walkthrough): stop the importance tag reading as a review finding

The "Critical" pill was painted in the status-error colour, so a stop marked
because it drives the change read as a severity reported against the code —
the one thing this feature never does. It is now "Key change", carries its
emphasis with weight and an outline rather than a status colour, and both tags
state their meaning in a tooltip. The panel links the guide from its header,
and the guide gained a section on what the tags mean and what they do not.

Also corrects two German strings that translated the noun "stop" as the verb.
This commit is contained in:
Bohdan Triapitsyn
2026-08-04 19:06:19 +03:00
parent 746e0d4abd
commit bcae0fcfc3
15 changed files with 124 additions and 19 deletions
@@ -11,6 +11,20 @@ Es erklärt und ordnet. Es bewertet Ihren Code nicht und fällt kein Urteil —
Öffnen Sie es über das **Walkthrough**-Symbol in der rechten Leiste oder über die Schaltfläche **AI walkthrough** in den Bereichen Changes und Pull Request. Beides öffnet nur das Panel; generiert wird erst, wenn Sie **Generate walkthrough** drücken.
## Wie ein Stop markiert ist
Jeder Stop benennt sein Thema, erklärt es in ein bis zwei Sätzen und zeigt danach genau den Code, den er beschreibt. Manche Stops tragen eine kleine Markierung neben dem Titel:
| Markierung | Bedeutung |
| --- | --- |
| **Kernänderung** | Dieser Stop trägt die eigentliche Änderung oder den größten Teil ihres Risikos. Lesen Sie ihn genau und zuerst. |
| **Kontext** | Eine unterstützende Änderung, damit der Rest verständlich bleibt. Kann überflogen werden. |
| *(ohne Markierung)* | Ein gewöhnlicher Schritt in der Lesereihenfolge. |
Die Markierung sagt, **wo Sie Ihre Aufmerksamkeit investieren sollten**, und nichts über die Qualität des Codes. Ein Stop wird nie markiert, weil darin etwas Falsches gefunden wurde — das Walkthrough meldet keine Funde, keine Schweregrade und keine Urteile. Wenn Code bewertet werden soll, ist das die Aktion **Review** in [Git & GitHub](/git/).
Die einzigen Markierungen, die tatsächlich auf ein Problem hinweisen, sind **Veraltet** und **Nicht abgedeckt** — und beide betreffen das Veralten des Walkthroughs selbst, nicht Ihren Code. Siehe unten.
## Was es prüfen kann
| Bereich | Was enthalten ist |
@@ -11,6 +11,20 @@ It explains and orders. It does not judge your code or hand out verdicts — tha
Open it from the **Walkthrough** icon in the right rail, or from the **AI walkthrough** button in the Changes and Pull Request panels. Both just open the panel; nothing is generated until you press **Generate walkthrough**.
## How a stop is marked
Each stop names what it is about, explains it in a sentence or two, and then shows exactly the code it describes. Some stops carry a small tag next to the title:
| Tag | What it means |
| --- | --- |
| **Key change** | This stop drives the rest of the change, or carries most of its risk. Read it closely and read it first. |
| **Context** | A supporting change, included so the rest makes sense. Safe to skim. |
| *(no tag)* | An ordinary step in the reading order. |
The tag is about **where to spend your attention**, not about the quality of the code. A stop is never marked because something was found wrong in it — the walkthrough reports no findings, no severities, and no verdicts. If you want code judged, that is the **Review** action in [Git & GitHub](/git/).
The only marks that do report a problem are **Outdated** and **Not covered**, and both are about the walkthrough itself going out of date rather than about your code — see below.
## What it can review
| Scope | What it covers |
@@ -2,6 +2,7 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Icon } from '@/components/icon/Icon';
import { FileTypeIcon } from '@/components/icons/FileTypeIcon';
import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useI18n } from '@/lib/i18n';
import { groupHunksByFile } from '@/lib/walkthrough/model';
import type { WalkthroughStopView, WalkthroughView } from '@/lib/walkthrough/model';
@@ -20,8 +21,13 @@ interface WalkthroughStreamProps {
wrapLines: boolean;
}
// Importance says where to spend attention, not what is wrong: a stop is marked
// because it drives the rest of the change, never because something was found in
// it. A red pill said the opposite — status colours are read as findings, and a
// walkthrough deliberately hands out no verdicts — so the emphasis is carried by
// weight and an outline instead, and the tooltip states the axis outright.
const IMPORTANCE_CLASS: Record<WalkthroughStopImportance, string> = {
critical: 'bg-status-error/10 text-status-error',
critical: 'border border-[var(--interactive-border)] font-medium text-foreground',
normal: 'bg-surface-muted text-muted-foreground',
context: 'bg-surface-muted text-muted-foreground',
};
@@ -41,11 +47,22 @@ const StopHeader = ({ stopView }: { stopView: WalkthroughStopView }) => {
exactly as tall as one without: vertical padding on a smaller type
size was pushing past the tallest element in the row. */}
{stop.importance !== 'normal' && (
<span className={cn('typography-micro flex h-5 items-center rounded px-1.5 leading-none', IMPORTANCE_CLASS[stop.importance])}>
{stop.importance === 'critical'
? t('walkthrough.importance.critical')
: t('walkthrough.importance.context')}
</span>
<Tooltip>
<TooltipTrigger
className={cn('typography-micro flex h-5 items-center rounded px-1.5 leading-none', IMPORTANCE_CLASS[stop.importance])}
>
{stop.importance === 'critical'
? t('walkthrough.importance.critical')
: t('walkthrough.importance.context')}
</TooltipTrigger>
<TooltipContent className="max-w-64">
<p className="typography-micro leading-tight">
{stop.importance === 'critical'
? t('walkthrough.importance.criticalHint')
: t('walkthrough.importance.contextHint')}
</p>
</TooltipContent>
</Tooltip>
)}
</div>
<p className="typography-body text-muted-foreground">{stop.prose}</p>
@@ -10,7 +10,9 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useI18n, type Locale } from '@/lib/i18n';
import { openExternalUrl } from '@/lib/url';
import { buildWalkthroughView } from '@/lib/walkthrough/model';
import type { WalkthroughSource, WalkthroughWorkingTreeScope } from '@/lib/walkthrough/types';
import { ModelSelector } from '@/components/sections/agents/ModelSelector';
@@ -41,6 +43,12 @@ interface WalkthroughViewProps {
const SCOPES: WalkthroughWorkingTreeScope[] = ['all', 'staged', 'working'];
// What a walkthrough is — and what it deliberately is not — cannot be read off
// the panel: the first question users asked about it was whether its marks were
// review findings. The guide answers that, so it is reachable from the surface
// itself rather than only from the release announcement.
const WALKTHROUGH_GUIDE_URL = 'https://docs.openchamber.dev/walkthrough/';
// DropdownMenuLabel defaults to the same size and weight as its items, which
// makes a heading read as another choice. This matches SelectLabel, the
// treatment used by the worktree picker.
@@ -524,6 +532,25 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => {
</DropdownMenu>
<div className="ml-auto flex min-w-0 items-center gap-1">
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
variant="ghost"
size="sm"
aria-label={t('walkthrough.help.guide')}
onClick={() => {
void openExternalUrl(WALKTHROUGH_GUIDE_URL);
}}
>
<Icon name="question" className="size-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p className="typography-micro leading-tight">{t('walkthrough.help.guide')}</p>
</TooltipContent>
</Tooltip>
{/* A walkthrough nobody can read is worth nothing, so the prose
language is a per-review choice like the model — defaulting to the
interface language, which is the best evidence of what the reader
+6 -3
View File
@@ -2853,17 +2853,20 @@ export const dict = {
'walkthrough.empty.title': 'Noch nichts vorhanden',
'walkthrough.empty.description': 'Wählen Sie Inhalte aus, um einen Walkthrough zu erstellen.',
'walkthrough.stale.banner': 'Der Code hat sich nach diesem Review geändert. Veraltete Schritte: {count}',
'walkthrough.stop.staleAll': 'Alle veralteten Inhalte stoppen',
'walkthrough.stop.staleAll': 'Der gesamte Code, den dieser Schritt beschrieben hat, hat sich geändert.',
'walkthrough.stop.stalePartial': 'Ein Teil des vom Schritt beschriebenen Codes hat sich geändert. Fehlende Teile: {count}',
'walkthrough.stop.staleShort': 'Veraltete stoppen',
'walkthrough.stop.staleShort': 'Veraltet',
'walkthrough.stop.noCode': 'Kein Code vorhanden',
'walkthrough.uncovered.title': 'Vom Review ausgelassene Änderungen: {count}',
'walkthrough.uncovered.description': 'Diese Bereiche wurden noch nicht in den Walkthrough aufgenommen.',
'walkthrough.toc.moreFiles': 'Weitere Dateien: {count}',
'walkthrough.toc.uncovered': 'Nicht abgedeckt: {count}',
'walkthrough.toc.resize': 'Größe ändern',
'walkthrough.importance.critical': 'Kritisch',
'walkthrough.importance.critical': 'Kernänderung',
'walkthrough.importance.criticalHint': 'Dieser Schritt trägt die eigentliche Änderung, lesen Sie ihn genau. Es ist kein in Ihrem Code gefundenes Problem.',
'walkthrough.importance.context': 'Kontext',
'walkthrough.importance.contextHint': 'Eine unterstützende Änderung, damit der Rest verständlich bleibt.',
'walkthrough.help.guide': 'So funktionieren Walkthroughs',
'walkthrough.blocked.noModel.title': 'Kein Modell ausgewählt',
'walkthrough.blocked.noModel.description': 'Wählen Sie zuerst ein Modell aus.',
'walkthrough.blocked.emptyDiff.title': 'Kein Diff vorhanden',
+4 -1
View File
@@ -1143,8 +1143,11 @@ export const dict = {
'walkthrough.toc.moreFiles': 'More files: {count}',
'walkthrough.toc.uncovered': 'Not covered: {count}',
'walkthrough.toc.resize': 'Resize the contents column',
'walkthrough.importance.critical': 'Critical',
'walkthrough.importance.critical': 'Key change',
'walkthrough.importance.criticalHint': 'This step drives the rest of the change, so read it closely. It is not a problem found in your code.',
'walkthrough.importance.context': 'Context',
'walkthrough.importance.contextHint': 'A supporting change, included so the rest makes sense.',
'walkthrough.help.guide': 'How walkthroughs work',
'walkthrough.blocked.noModel.title': 'No small model available',
'walkthrough.blocked.noModel.description': 'Sign in to a model provider to generate a review.',
'walkthrough.blocked.emptyDiff.title': 'Nothing to review',
+4 -1
View File
@@ -1144,8 +1144,11 @@ export const dict: Record<I18nKey, string> = {
"walkthrough.toc.moreFiles": "Más archivos: {count}",
"walkthrough.toc.uncovered": "Sin cubrir: {count}",
"walkthrough.toc.resize": "Cambiar el ancho de la columna de contenidos",
"walkthrough.importance.critical": "Crítico",
"walkthrough.importance.critical": "Cambio clave",
"walkthrough.importance.criticalHint": "Este paso impulsa el resto del cambio, así que léelo con atención. No es un problema detectado en tu código.",
"walkthrough.importance.context": "Contexto",
"walkthrough.importance.contextHint": "Un cambio de apoyo, incluido para que el resto tenga sentido.",
"walkthrough.help.guide": "Cómo funcionan los walkthroughs",
"walkthrough.blocked.noModel.title": "No hay ningún modelo pequeño disponible",
"walkthrough.blocked.noModel.description": "Inicia sesión en un proveedor de modelos para generar una revisión.",
"walkthrough.blocked.emptyDiff.title": "Nada que revisar",
+4 -1
View File
@@ -968,8 +968,11 @@ export const dict = {
'walkthrough.toc.moreFiles': 'Autres fichiers : {count}',
'walkthrough.toc.uncovered': 'Non traité : {count}',
'walkthrough.toc.resize': 'Redimensionner la colonne du sommaire',
'walkthrough.importance.critical': 'Critique',
'walkthrough.importance.critical': 'Changement clé',
'walkthrough.importance.criticalHint': "Cette étape porte l'essentiel du changement, lisez-la attentivement. Ce n'est pas un problème détecté dans votre code.",
'walkthrough.importance.context': 'Contexte',
'walkthrough.importance.contextHint': 'Un changement de soutien, présent pour que le reste ait du sens.',
'walkthrough.help.guide': 'Comment fonctionnent les walkthroughs',
'walkthrough.blocked.noModel.title': 'Aucun petit modèle disponible',
'walkthrough.blocked.noModel.description': 'Connectez-vous à un fournisseur de modèles pour générer une revue.',
'walkthrough.blocked.emptyDiff.title': 'Rien à examiner',
+4 -1
View File
@@ -1140,8 +1140,11 @@ export const dict: Record<I18nKey, string> = {
'walkthrough.toc.moreFiles': 'その他のファイル: {count}',
'walkthrough.toc.uncovered': '未対応: {count}',
'walkthrough.toc.resize': '目次の列幅を変更',
'walkthrough.importance.critical': '重要',
'walkthrough.importance.critical': '主要な変更',
'walkthrough.importance.criticalHint': 'このステップが変更全体を動かしているため、じっくり読んでください。コードで見つかった問題ではありません。',
'walkthrough.importance.context': '補足',
'walkthrough.importance.contextHint': '全体を理解するために添えられた補助的な変更です。',
'walkthrough.help.guide': 'ウォークスルーの仕組み',
'walkthrough.blocked.noModel.title': '利用できるスモールモデルがありません',
'walkthrough.blocked.noModel.description': 'レビューを生成するにはモデルプロバイダーにサインインしてください。',
'walkthrough.blocked.emptyDiff.title': 'レビュー対象がありません',
+4 -1
View File
@@ -1144,8 +1144,11 @@ export const dict: Record<I18nKey, string> = {
'walkthrough.toc.moreFiles': '다른 파일: {count}',
'walkthrough.toc.uncovered': '미포함: {count}',
'walkthrough.toc.resize': '목차 열 너비 조절',
'walkthrough.importance.critical': '중요',
'walkthrough.importance.critical': '핵심 변경',
'walkthrough.importance.criticalHint': '이 단계가 변경 전체를 이끌고 있으니 꼼꼼히 읽어 보세요. 코드에서 발견된 문제가 아닙니다.',
'walkthrough.importance.context': '참고',
'walkthrough.importance.contextHint': '나머지를 이해하는 데 도움이 되도록 함께 실은 보조 변경입니다.',
'walkthrough.help.guide': '워크스루 작동 방식',
'walkthrough.blocked.noModel.title': '사용할 수 있는 스몰 모델이 없습니다',
'walkthrough.blocked.noModel.description': '리뷰를 생성하려면 모델 제공자에 로그인하세요.',
'walkthrough.blocked.emptyDiff.title': '리뷰할 내용이 없습니다',
+4 -1
View File
@@ -1456,8 +1456,11 @@ export const dict: Record<I18nKey, string> = {
'walkthrough.toc.moreFiles': 'Więcej plików: {count}',
'walkthrough.toc.uncovered': 'Nieuwzględnione: {count}',
'walkthrough.toc.resize': 'Zmień szerokość kolumny spisu treści',
'walkthrough.importance.critical': 'Krytyczne',
'walkthrough.importance.critical': 'Kluczowa zmiana',
'walkthrough.importance.criticalHint': 'Ten krok napędza resztę zmiany, więc przeczytaj go uważnie. To nie jest problem znaleziony w Twoim kodzie.',
'walkthrough.importance.context': 'Kontekst',
'walkthrough.importance.contextHint': 'Zmiana pomocnicza, dołączona po to, by reszta miała sens.',
'walkthrough.help.guide': 'Jak działają walkthroughy',
'walkthrough.blocked.noModel.title': 'Brak dostępnego małego modelu',
'walkthrough.blocked.noModel.description': 'Zaloguj się u dostawcy modeli, aby wygenerować przegląd.',
'walkthrough.blocked.emptyDiff.title': 'Nie ma czego przeglądać',
+4 -1
View File
@@ -1144,8 +1144,11 @@ export const dict: Record<I18nKey, string> = {
"walkthrough.toc.moreFiles": "Mais arquivos: {count}",
"walkthrough.toc.uncovered": "Sem cobertura: {count}",
"walkthrough.toc.resize": "Redimensionar a coluna de conteúdo",
"walkthrough.importance.critical": "Crítico",
"walkthrough.importance.critical": "Mudança principal",
"walkthrough.importance.criticalHint": "Este passo conduz o restante da mudança, então leia com atenção. Não é um problema encontrado no seu código.",
"walkthrough.importance.context": "Contexto",
"walkthrough.importance.contextHint": "Uma mudança de apoio, incluída para que o restante faça sentido.",
"walkthrough.help.guide": "Como funcionam os walkthroughs",
"walkthrough.blocked.noModel.title": "Nenhum modelo pequeno disponível",
"walkthrough.blocked.noModel.description": "Entre em um provedor de modelos para gerar uma revisão.",
"walkthrough.blocked.emptyDiff.title": "Nada para revisar",
+4 -1
View File
@@ -1144,8 +1144,11 @@ export const dict: Record<I18nKey, string> = {
"walkthrough.toc.moreFiles": "Ще файлів: {count}",
"walkthrough.toc.uncovered": "Не описано: {count}",
"walkthrough.toc.resize": "Змінити ширину колонки змісту",
"walkthrough.importance.critical": "Критично",
"walkthrough.importance.critical": "Ключова зміна",
"walkthrough.importance.criticalHint": "Цей крок веде за собою решту зміни, тож прочитайте його уважно. Це не знайдена у вашому коді проблема.",
"walkthrough.importance.context": "Контекст",
"walkthrough.importance.contextHint": "Допоміжна зміна, додана, щоб решта мала сенс.",
"walkthrough.help.guide": "Як працюють walkthrough",
"walkthrough.blocked.noModel.title": "Немає доступної small model",
"walkthrough.blocked.noModel.description": "Увійдіть до провайдера моделей, щоб створити розбір.",
"walkthrough.blocked.emptyDiff.title": "Немає що оглядати",
+4 -1
View File
@@ -1144,8 +1144,11 @@ export const dict: Record<I18nKey, string> = {
'walkthrough.toc.moreFiles': '其他文件:{count}',
'walkthrough.toc.uncovered': '未涵盖:{count}',
'walkthrough.toc.resize': '调整目录栏宽度',
'walkthrough.importance.critical': '关键',
'walkthrough.importance.critical': '关键改动',
'walkthrough.importance.criticalHint': '这一步带动了其余改动,值得仔细阅读。它不是在你的代码中发现的问题。',
'walkthrough.importance.context': '背景',
'walkthrough.importance.contextHint': '辅助性的改动,列在这里是为了让其余部分说得通。',
'walkthrough.help.guide': 'Walkthrough 的工作方式',
'walkthrough.blocked.noModel.title': '没有可用的小模型',
'walkthrough.blocked.noModel.description': '请登录模型提供方后再生成评审。',
'walkthrough.blocked.emptyDiff.title': '没有可评审的内容',
+4 -1
View File
@@ -1156,8 +1156,11 @@ export const dict: Record<I18nKey, string> = {
'walkthrough.toc.moreFiles': '其他檔案:{count}',
'walkthrough.toc.uncovered': '未涵蓋:{count}',
'walkthrough.toc.resize': '調整目錄欄寬度',
'walkthrough.importance.critical': '關鍵',
'walkthrough.importance.critical': '關鍵變更',
'walkthrough.importance.criticalHint': '這一步帶動了其餘變更,值得仔細閱讀。它不是在你的程式碼中發現的問題。',
'walkthrough.importance.context': '背景',
'walkthrough.importance.contextHint': '輔助性的變更,列在這裡是為了讓其餘部分說得通。',
'walkthrough.help.guide': 'Walkthrough 的運作方式',
'walkthrough.blocked.noModel.title': '沒有可用的小模型',
'walkthrough.blocked.noModel.description': '請先登入模型供應商再產生審閱。',
'walkthrough.blocked.emptyDiff.title': '沒有可審閱的內容',