diff --git a/CHANGELOG.md b/CHANGELOG.md index e3b2859..1922f9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,20 @@ lockstep. ## Unreleased +### Changed (usertest low-findings tail) + +- **Honest hero badge.** The store hero wears "TODAY"/"HEUTE" only + for an operator-accepted story; the compiled-in fallback deck has + no date binding and now says "FEATURED"/"EMPFOHLEN". +- **Audit filter chips in UI type.** The Alle/Flow/Schritt/Modul + chips drop the monospace styling — mono stays reserved for paths + and identifiers. +- **One verb for the chain check (DE).** "Hash-Kette geprüft" is the + confirmation everywhere (audit header, doctor pill); "intakt" + remains the state headline. English was already consistent. +- **Readable sealed-area status.** The "stopped" label in the + workspace switcher gets a modest contrast bump. + ### Changed (usertest panel 2026-07-17, 14 personas — all confirmed findings) - **Install trust gate.** One confirmation dialog before every module diff --git a/lib/data/about_info.dart b/lib/data/about_info.dart index 60ce76e..e5cd30a 100644 --- a/lib/data/about_info.dart +++ b/lib/data/about_info.dart @@ -4,7 +4,7 @@ /// Studio's own build version. Bump on every UI release so the /// running app self-identifies. -const String kStudioVersion = '0.72.0'; +const String kStudioVersion = '0.72.1'; const String kProductName = 'Ch∆In Studio'; const String kVendorName = 'Flemming.AI (F∆I)'; diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index a84c6ef..c8c92f5 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -374,6 +374,7 @@ "storesManagerNotAvailableHint": "Der Anbieter hat diesen Store-Index noch nicht veröffentlicht. Sobald er das tut, ist er installierbar.", "storesSuggestedReclaimDesc": "Recl∆Im — Module für Rechts- und Pflichten-Reform-Mapping", "storeTodayBadge": "HEUTE", + "storeFeaturedBadge": "EMPFOHLEN", "storeTodayDeck": "Von der Ch∆In-Redaktion", "storeTodayDismissTooltip": "Für diese Sitzung ausblenden", "storePillInstalled": "installiert", @@ -629,7 +630,7 @@ } } }, - "auditHashChainVerified": "Hash-Kette verifiziert", + "auditHashChainVerified": "Hash-Kette geprüft", "auditDetailHeader": "DETAIL", "auditAskingFull": "Frage an die konfigurierte System-AI läuft…", "auditFixLabel": "FIX", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index fccc1a2..f0cdbcb 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -392,6 +392,7 @@ "storesManagerNotAvailableHint": "The provider hasn't published this store index yet. It will become installable once they do.", "storesSuggestedReclaimDesc": "Recl∆Im — modules for law & duty reform-mapping", "storeTodayBadge": "TODAY", + "storeFeaturedBadge": "FEATURED", "storeTodayDeck": "From the Ch∆In editor", "storeTodayDismissTooltip": "Hide for this session", "storePillInstalled": "installed", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index f5c1e67..79717f0 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -1766,6 +1766,12 @@ abstract class AppLocalizations { /// **'TODAY'** String get storeTodayBadge; + /// No description provided for @storeFeaturedBadge. + /// + /// In en, this message translates to: + /// **'FEATURED'** + String get storeFeaturedBadge; + /// No description provided for @storeTodayDeck. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index e0a531c..c281544 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -957,6 +957,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get storeTodayBadge => 'HEUTE'; + @override + String get storeFeaturedBadge => 'EMPFOHLEN'; + @override String get storeTodayDeck => 'Von der Ch∆In-Redaktion'; @@ -1275,7 +1278,7 @@ class AppLocalizationsDe extends AppLocalizations { } @override - String get auditHashChainVerified => 'Hash-Kette verifiziert'; + String get auditHashChainVerified => 'Hash-Kette geprüft'; @override String get auditDetailHeader => 'DETAIL'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 4dae3e9..d177ddc 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -974,6 +974,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get storeTodayBadge => 'TODAY'; + @override + String get storeFeaturedBadge => 'FEATURED'; + @override String get storeTodayDeck => 'From the Ch∆In editor'; diff --git a/lib/pages/audit.dart b/lib/pages/audit.dart index ad7ebcf..4497bf3 100644 --- a/lib/pages/audit.dart +++ b/lib/pages/audit.dart @@ -620,9 +620,11 @@ class _ChipButtonState extends State<_ChipButton> { ), child: Text( widget.label, - style: ChainTheme.mono( - size: 11, - weight: widget.selected ? FontWeight.w500 : FontWeight.w400, + // UI label, not a value — mono is reserved for + // paths/identifiers (usertest finding: the chips + // read as foreign bodies in the header). + style: theme.textTheme.labelMedium?.copyWith( + fontWeight: widget.selected ? FontWeight.w600 : FontWeight.w400, color: fg, ), ), diff --git a/lib/pages/store.dart b/lib/pages/store.dart index aa61e3c..f2dba77 100644 --- a/lib/pages/store.dart +++ b/lib/pages/store.dart @@ -3207,6 +3207,13 @@ class _ScreenshotPlaceholder extends StatelessWidget { /// not abstract platform philosophy. Architecture education /// (sandbox model, hash-chained audit, air-gap posture) lives /// on the dedicated Welcome page, not in the store carousel. +/// Whether the hero deck may wear the date-bound "TODAY" badge. +/// Only a single, operator-accepted story qualifies — the +/// compiled-in fallback deck rotates unchanged across sessions +/// and must not claim freshness ("FEATURED" instead). Top-level +/// so the policy stays unit-testable. +bool storeDeckIsAcceptedToday(int totalCount) => totalCount == 1; + const List _kFallbackTodayStories = [ TodayStoryData( badgeEn: 'MCP', @@ -3433,7 +3440,12 @@ class _StoreTodayHero extends StatelessWidget { runSpacing: 4, crossAxisAlignment: WrapCrossAlignment.center, children: [ - ChainPill(label: l.storeTodayBadge, tone: ChainPillTone.accent), + ChainPill( + label: storeDeckIsAcceptedToday(totalCount) + ? l.storeTodayBadge + : l.storeFeaturedBadge, + tone: ChainPillTone.accent, + ), Text( badge, style: theme.textTheme.labelSmall?.copyWith( diff --git a/lib/widgets/chain_workspace_switcher.dart b/lib/widgets/chain_workspace_switcher.dart index b9c85d6..48df296 100644 --- a/lib/widgets/chain_workspace_switcher.dart +++ b/lib/widgets/chain_workspace_switcher.dart @@ -149,9 +149,12 @@ class ChainWorkspaceSwitcher extends StatelessWidget { ? l.workspaceSealedRunning : l.workspaceSealedStopped, style: theme.textTheme.labelSmall?.copyWith( + // Secondary but readable — onSurfaceVariant + // fell below comfortable contrast at this + // size (usertest finding). color: a.running ? ChainColors.success - : theme.colorScheme.onSurfaceVariant, + : theme.colorScheme.onSurface.withValues(alpha: 0.8), ), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 5e49b08..c2e33fd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: chain_studio description: "Ch∆In Studio — desktop GUI for the Ch∆In hub" publish_to: 'none' -version: 0.72.0 +version: 0.72.1 environment: sdk: ^3.11.0-200.1.beta diff --git a/test/store_today_badge_test.dart b/test/store_today_badge_test.dart new file mode 100644 index 0000000..f7fcf29 --- /dev/null +++ b/test/store_today_badge_test.dart @@ -0,0 +1,15 @@ +import 'package:chain_studio/pages/store.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('store hero badge policy', () { + test('a single operator-accepted story may claim TODAY', () { + expect(storeDeckIsAcceptedToday(1), isTrue); + }); + + test('the rotating fallback deck must not claim TODAY', () { + expect(storeDeckIsAcceptedToday(2), isFalse); + expect(storeDeckIsAcceptedToday(8), isFalse); + }); + }); +}