fix(approvals,l10n,theme): usertest findings — localized prompts, no-data confirm, .chain log path, honest wording, AA contrast
Some checks failed
Security / Security check (push) Failing after 2s

- approvals: empty/legacy hub prompts render the localized fallback;
  approving without show: data asks for conscious confirmation first
- chain_log: write to ~/.chain/logs/studio-errors.log (was .fai),
  one-time best-effort migration of the legacy file + rotation sibling
- l10n: 'manipulationssicher' -> 'manipulationserkennend', neutral
  WORM-1 blurb, doctor pill 'Integritätskette v1', federation hint
  says the CA authenticates the first connect (DE+EN)
- theme: muted text token now >=4.5:1 on canvas, cards and elevated
  dark surfaces (was 3.7:1 on cards)

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-11 02:38:24 +02:00
parent 0fda2600ad
commit bb606a8b23
10 changed files with 167 additions and 26 deletions

View file

@ -30,7 +30,7 @@
"welcomeTrustHeader": "TRUST-POSTURE",
"welcomeTrustSandboxTitle": "Sandbox von Anfang an",
"welcomeTrustSandboxBody": "Jedes Modul bringt eine explizite Berechtigungsliste mit — Netzwerk-Endpunkte, Dateien, Umgebungsvariablen. Der Hub setzt sie durch; ohne Operator-Freigabe verlässt nichts die Sandbox.",
"welcomeTrustAuditTitle": "Manipulationssicheres Audit-Log",
"welcomeTrustAuditTitle": "Manipulationserkennendes Audit-Log",
"welcomeTrustAuditBody": "Flow-Läufe, Installationen, Deinstallationen, Freigabe-Entscheidungen — alles wird in ein hash-verkettetes Audit-Log geschrieben. Die Diagnose-Seite verifiziert die Kette bei jedem Laden komplett.",
"welcomeTrustAirgapTitle": "Air-Gap-tauglich",
"welcomeTrustAirgapBody": "Der gesamte Hub steckt in einem einzigen Binary für Linux, macOS und Windows. Sobald ein Modul installiert ist, läuft der Flow, der es nutzt, ohne weiteren Netzwerkzugriff — ideal für regulierte Umgebungen.",
@ -40,8 +40,8 @@
"welcomeDocArchitectureBlurb": "Hub, Modul, Flow — und wie die drei zusammenpassen.",
"welcomeDocSecurityTitle": "Sandbox-Modell",
"welcomeDocSecurityBlurb": "Was ein Modul deklariert, was der Operator deckelt, was der Hub durchsetzt.",
"welcomeDocAuditTitle": "Manipulationssicheres Audit-Log",
"welcomeDocAuditBlurb": "Wie die Hash-Kette funktioniert und warum WORM-1 für KRITIS reicht.",
"welcomeDocAuditTitle": "Manipulationserkennendes Audit-Log",
"welcomeDocAuditBlurb": "Wie die Hash-Kette nachträgliche Änderungen erkennbar macht — und was die Integritätsstufe WORM-1 leistet (und was nicht).",
"welcomeDocFlowsTitle": "Flow-Komposition",
"welcomeDocFlowsBlurb": "YAML-Grundlagen, Templating-Referenz, das Extract→Summarize-Beispiel.",
"welcomeDocApprovalsTitle": "Freigaben",
@ -1046,6 +1046,9 @@
"approvalsPillExpired": "abgelaufen",
"approvalsPayloadPreview": "ZU PRÜFENDE DATEN",
"approvalsNoPayload": "Keine Daten zum Prüfen angehängt. Der system.approval-Schritt des Flows bestimmt über sein \"show:\"-Feld, was angezeigt wird — setze es, um die Daten hinter dieser Entscheidung sichtbar zu machen.",
"approvalsNoDataConfirmTitle": "Ohne Prüfdaten freigeben?",
"approvalsNoDataConfirmBody": "Dieser Flow hat bewusst keine Prüfdaten hinterlegt (kein \"show:\" am Freigabe-Schritt). Du kannst trotzdem freigeben — entscheidest dann aber, ohne die Daten hinter dieser Entscheidung gesehen zu haben.",
"approvalsNoDataConfirmAction": "Trotzdem freigeben",
"approvalsRequestFallback": "Freigabe für diesen Schritt erforderlich",
"approvalsFlowStepMeta": "Flow: {flow} · Schritt: {step}",
"approvalsApproveButton": "Freigeben",
@ -1193,7 +1196,7 @@
}
}
},
"doctorChainPillOk": "WORM-1",
"doctorChainPillOk": "Integritätskette v1",
"doctorChainPillTamper": "MANIPULIERT",
"doctorVerifyNow": "Jetzt prüfen",
"doctorRestart": "Neustart",
@ -1661,5 +1664,5 @@
"federationTokenLabel": "Bootstrap-Token (einmalig)",
"federationConfigLabel": "Satelliten-Konfiguration (in den Satelliten einfügen)",
"federationCopied": "In die Zwischenablage kopiert",
"federationEnrollmentHint": "Übergib das Token dem Satelliten-Betreiber über einen sicheren Kanal. Die mitgelieferte CA macht den ersten Connect des Satelliten manipulationssicher."
"federationEnrollmentHint": "Übergib das Token dem Satelliten-Betreiber über einen sicheren Kanal. Die mitgelieferte CA authentifiziert den ersten Connect des Satelliten."
}

View file

@ -49,7 +49,7 @@
"welcomeDocSecurityTitle": "Sandbox model",
"welcomeDocSecurityBlurb": "What a module declares, what the operator caps, what the hub enforces.",
"welcomeDocAuditTitle": "Tamper-evident audit log",
"welcomeDocAuditBlurb": "How the hash chain works and why WORM-1 is enough for KRITIS.",
"welcomeDocAuditBlurb": "How the hash chain makes later edits detectable — and what integrity level WORM-1 does (and does not) provide.",
"welcomeDocFlowsTitle": "Flow composition",
"welcomeDocFlowsBlurb": "YAML basics, templating reference, the extract→summarize example.",
"welcomeDocApprovalsTitle": "Approvals",
@ -1064,6 +1064,9 @@
"approvalsPillExpired": "expired",
"approvalsPayloadPreview": "DATA TO REVIEW",
"approvalsNoPayload": "No data was attached for review. The flow's approval step chooses what to show via its \"show:\" field — set it to surface the data behind this decision.",
"approvalsNoDataConfirmTitle": "Approve without review data?",
"approvalsNoDataConfirmBody": "This flow deliberately attached no review data (no \"show:\" on its approval step). You can still approve — but you would be deciding without seeing the data behind this decision.",
"approvalsNoDataConfirmAction": "Approve anyway",
"approvalsRequestFallback": "Approval required for this step",
"approvalsFlowStepMeta": "Flow: {flow} · Step: {step}",
"@approvalsFlowStepMeta": {
@ -1217,7 +1220,7 @@
}
}
},
"doctorChainPillOk": "WORM-1",
"doctorChainPillOk": "Integrity chain v1",
"doctorChainPillTamper": "TAMPER",
"doctorVerifyNow": "Verify now",
"doctorRestart": "Restart",
@ -1700,5 +1703,5 @@
"federationTokenLabel": "Bootstrap token (single use)",
"federationConfigLabel": "Satellite config (paste into the satellite)",
"federationCopied": "Copied to clipboard",
"federationEnrollmentHint": "Hand the token to the satellite operator over a secure channel. The bundled CA makes the satellite's first connect tamper-proof."
"federationEnrollmentHint": "Hand the token to the satellite operator over a secure channel. The bundled CA authenticates the satellite's first connect."
}

View file

@ -347,7 +347,7 @@ abstract class AppLocalizations {
/// No description provided for @welcomeDocAuditBlurb.
///
/// In en, this message translates to:
/// **'How the hash chain works and why WORM-1 is enough for KRITIS.'**
/// **'How the hash chain makes later edits detectable — and what integrity level WORM-1 does (and does not) provide.'**
String get welcomeDocAuditBlurb;
/// No description provided for @welcomeDocFlowsTitle.
@ -3254,6 +3254,24 @@ abstract class AppLocalizations {
/// **'No data was attached for review. The flow\'s approval step chooses what to show via its \"show:\" field — set it to surface the data behind this decision.'**
String get approvalsNoPayload;
/// No description provided for @approvalsNoDataConfirmTitle.
///
/// In en, this message translates to:
/// **'Approve without review data?'**
String get approvalsNoDataConfirmTitle;
/// No description provided for @approvalsNoDataConfirmBody.
///
/// In en, this message translates to:
/// **'This flow deliberately attached no review data (no \"show:\" on its approval step). You can still approve — but you would be deciding without seeing the data behind this decision.'**
String get approvalsNoDataConfirmBody;
/// No description provided for @approvalsNoDataConfirmAction.
///
/// In en, this message translates to:
/// **'Approve anyway'**
String get approvalsNoDataConfirmAction;
/// No description provided for @approvalsRequestFallback.
///
/// In en, this message translates to:
@ -3527,7 +3545,7 @@ abstract class AppLocalizations {
/// No description provided for @doctorChainPillOk.
///
/// In en, this message translates to:
/// **'WORM-1'**
/// **'Integrity chain v1'**
String get doctorChainPillOk;
/// No description provided for @doctorChainPillTamper.
@ -4870,7 +4888,7 @@ abstract class AppLocalizations {
/// No description provided for @federationEnrollmentHint.
///
/// In en, this message translates to:
/// **'Hand the token to the satellite operator over a secure channel. The bundled CA makes the satellite\'s first connect tamper-proof.'**
/// **'Hand the token to the satellite operator over a secure channel. The bundled CA authenticates the satellite\'s first connect.'**
String get federationEnrollmentHint;
}

View file

@ -110,7 +110,7 @@ class AppLocalizationsDe extends AppLocalizations {
'Jedes Modul bringt eine explizite Berechtigungsliste mit — Netzwerk-Endpunkte, Dateien, Umgebungsvariablen. Der Hub setzt sie durch; ohne Operator-Freigabe verlässt nichts die Sandbox.';
@override
String get welcomeTrustAuditTitle => 'Manipulationssicheres Audit-Log';
String get welcomeTrustAuditTitle => 'Manipulationserkennendes Audit-Log';
@override
String get welcomeTrustAuditBody =>
@ -145,11 +145,11 @@ class AppLocalizationsDe extends AppLocalizations {
'Was ein Modul deklariert, was der Operator deckelt, was der Hub durchsetzt.';
@override
String get welcomeDocAuditTitle => 'Manipulationssicheres Audit-Log';
String get welcomeDocAuditTitle => 'Manipulationserkennendes Audit-Log';
@override
String get welcomeDocAuditBlurb =>
'Wie die Hash-Kette funktioniert und warum WORM-1 für KRITIS reicht.';
'Wie die Hash-Kette nachträgliche Änderungen erkennbar macht — und was die Integritätsstufe WORM-1 leistet (und was nicht).';
@override
String get welcomeDocFlowsTitle => 'Flow-Komposition';
@ -1871,6 +1871,16 @@ class AppLocalizationsDe extends AppLocalizations {
String get approvalsNoPayload =>
'Keine Daten zum Prüfen angehängt. Der system.approval-Schritt des Flows bestimmt über sein \"show:\"-Feld, was angezeigt wird — setze es, um die Daten hinter dieser Entscheidung sichtbar zu machen.';
@override
String get approvalsNoDataConfirmTitle => 'Ohne Prüfdaten freigeben?';
@override
String get approvalsNoDataConfirmBody =>
'Dieser Flow hat bewusst keine Prüfdaten hinterlegt (kein \"show:\" am Freigabe-Schritt). Du kannst trotzdem freigeben — entscheidest dann aber, ohne die Daten hinter dieser Entscheidung gesehen zu haben.';
@override
String get approvalsNoDataConfirmAction => 'Trotzdem freigeben';
@override
String get approvalsRequestFallback =>
'Freigabe für diesen Schritt erforderlich';
@ -2043,7 +2053,7 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get doctorChainPillOk => 'WORM-1';
String get doctorChainPillOk => 'Integritätskette v1';
@override
String get doctorChainPillTamper => 'MANIPULIERT';
@ -2860,5 +2870,5 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get federationEnrollmentHint =>
'Übergib das Token dem Satelliten-Betreiber über einen sicheren Kanal. Die mitgelieferte CA macht den ersten Connect des Satelliten manipulationssicher.';
'Übergib das Token dem Satelliten-Betreiber über einen sicheren Kanal. Die mitgelieferte CA authentifiziert den ersten Connect des Satelliten.';
}

View file

@ -150,7 +150,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get welcomeDocAuditBlurb =>
'How the hash chain works and why WORM-1 is enough for KRITIS.';
'How the hash chain makes later edits detectable — and what integrity level WORM-1 does (and does not) provide.';
@override
String get welcomeDocFlowsTitle => 'Flow composition';
@ -1882,6 +1882,16 @@ class AppLocalizationsEn extends AppLocalizations {
String get approvalsNoPayload =>
'No data was attached for review. The flow\'s approval step chooses what to show via its \"show:\" field — set it to surface the data behind this decision.';
@override
String get approvalsNoDataConfirmTitle => 'Approve without review data?';
@override
String get approvalsNoDataConfirmBody =>
'This flow deliberately attached no review data (no \"show:\" on its approval step). You can still approve — but you would be deciding without seeing the data behind this decision.';
@override
String get approvalsNoDataConfirmAction => 'Approve anyway';
@override
String get approvalsRequestFallback => 'Approval required for this step';
@ -2052,7 +2062,7 @@ class AppLocalizationsEn extends AppLocalizations {
}
@override
String get doctorChainPillOk => 'WORM-1';
String get doctorChainPillOk => 'Integrity chain v1';
@override
String get doctorChainPillTamper => 'TAMPER';
@ -2863,5 +2873,5 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get federationEnrollmentHint =>
'Hand the token to the satellite operator over a secure channel. The bundled CA makes the satellite\'s first connect tamper-proof.';
'Hand the token to the satellite operator over a secure channel. The bundled CA authenticates the satellite\'s first connect.';
}