fix(store,audit,workspace): usertest low-findings tail (0.72.1)
Some checks failed
Security / Security check (push) Failing after 1s

- Store hero: 'TODAY' badge only for an operator-accepted story; the
  rotating compiled-in fallback deck now says 'FEATURED' (no false
  freshness claim). Policy as a top-level function with unit tests.
- Audit filter chips: standard label typography instead of mono —
  mono stays reserved for paths and identifiers.
- DE chain wording: 'Hash-Kette geprüft' as the one confirmation term
  (audit header now matches the doctor pill); 'intakt' stays the
  state headline. EN was already consistent.
- Workspace switcher: contrast bump for the sealed-area 'stopped'
  label.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-18 01:08:09 +02:00
parent 6152c80c84
commit ae8fdcc762
12 changed files with 69 additions and 9 deletions

View file

@ -6,6 +6,20 @@ lockstep.
## Unreleased ## 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) ### Changed (usertest panel 2026-07-17, 14 personas — all confirmed findings)
- **Install trust gate.** One confirmation dialog before every module - **Install trust gate.** One confirmation dialog before every module

View file

@ -4,7 +4,7 @@
/// Studio's own build version. Bump on every UI release so the /// Studio's own build version. Bump on every UI release so the
/// running app self-identifies. /// running app self-identifies.
const String kStudioVersion = '0.72.0'; const String kStudioVersion = '0.72.1';
const String kProductName = 'Ch∆In Studio'; const String kProductName = 'Ch∆In Studio';
const String kVendorName = 'Flemming.AI (F∆I)'; const String kVendorName = 'Flemming.AI (F∆I)';

View file

@ -374,6 +374,7 @@
"storesManagerNotAvailableHint": "Der Anbieter hat diesen Store-Index noch nicht veröffentlicht. Sobald er das tut, ist er installierbar.", "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", "storesSuggestedReclaimDesc": "Recl∆Im — Module für Rechts- und Pflichten-Reform-Mapping",
"storeTodayBadge": "HEUTE", "storeTodayBadge": "HEUTE",
"storeFeaturedBadge": "EMPFOHLEN",
"storeTodayDeck": "Von der Ch∆In-Redaktion", "storeTodayDeck": "Von der Ch∆In-Redaktion",
"storeTodayDismissTooltip": "Für diese Sitzung ausblenden", "storeTodayDismissTooltip": "Für diese Sitzung ausblenden",
"storePillInstalled": "installiert", "storePillInstalled": "installiert",
@ -629,7 +630,7 @@
} }
} }
}, },
"auditHashChainVerified": "Hash-Kette verifiziert", "auditHashChainVerified": "Hash-Kette geprüft",
"auditDetailHeader": "DETAIL", "auditDetailHeader": "DETAIL",
"auditAskingFull": "Frage an die konfigurierte System-AI läuft…", "auditAskingFull": "Frage an die konfigurierte System-AI läuft…",
"auditFixLabel": "FIX", "auditFixLabel": "FIX",

View file

@ -392,6 +392,7 @@
"storesManagerNotAvailableHint": "The provider hasn't published this store index yet. It will become installable once they do.", "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", "storesSuggestedReclaimDesc": "Recl∆Im — modules for law & duty reform-mapping",
"storeTodayBadge": "TODAY", "storeTodayBadge": "TODAY",
"storeFeaturedBadge": "FEATURED",
"storeTodayDeck": "From the Ch∆In editor", "storeTodayDeck": "From the Ch∆In editor",
"storeTodayDismissTooltip": "Hide for this session", "storeTodayDismissTooltip": "Hide for this session",
"storePillInstalled": "installed", "storePillInstalled": "installed",

View file

@ -1766,6 +1766,12 @@ abstract class AppLocalizations {
/// **'TODAY'** /// **'TODAY'**
String get storeTodayBadge; String get storeTodayBadge;
/// No description provided for @storeFeaturedBadge.
///
/// In en, this message translates to:
/// **'FEATURED'**
String get storeFeaturedBadge;
/// No description provided for @storeTodayDeck. /// No description provided for @storeTodayDeck.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

View file

@ -957,6 +957,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get storeTodayBadge => 'HEUTE'; String get storeTodayBadge => 'HEUTE';
@override
String get storeFeaturedBadge => 'EMPFOHLEN';
@override @override
String get storeTodayDeck => 'Von der Ch∆In-Redaktion'; String get storeTodayDeck => 'Von der Ch∆In-Redaktion';
@ -1275,7 +1278,7 @@ class AppLocalizationsDe extends AppLocalizations {
} }
@override @override
String get auditHashChainVerified => 'Hash-Kette verifiziert'; String get auditHashChainVerified => 'Hash-Kette geprüft';
@override @override
String get auditDetailHeader => 'DETAIL'; String get auditDetailHeader => 'DETAIL';

View file

@ -974,6 +974,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get storeTodayBadge => 'TODAY'; String get storeTodayBadge => 'TODAY';
@override
String get storeFeaturedBadge => 'FEATURED';
@override @override
String get storeTodayDeck => 'From the Ch∆In editor'; String get storeTodayDeck => 'From the Ch∆In editor';

View file

@ -620,9 +620,11 @@ class _ChipButtonState extends State<_ChipButton> {
), ),
child: Text( child: Text(
widget.label, widget.label,
style: ChainTheme.mono( // UI label, not a value mono is reserved for
size: 11, // paths/identifiers (usertest finding: the chips
weight: widget.selected ? FontWeight.w500 : FontWeight.w400, // read as foreign bodies in the header).
style: theme.textTheme.labelMedium?.copyWith(
fontWeight: widget.selected ? FontWeight.w600 : FontWeight.w400,
color: fg, color: fg,
), ),
), ),

View file

@ -3207,6 +3207,13 @@ class _ScreenshotPlaceholder extends StatelessWidget {
/// not abstract platform philosophy. Architecture education /// not abstract platform philosophy. Architecture education
/// (sandbox model, hash-chained audit, air-gap posture) lives /// (sandbox model, hash-chained audit, air-gap posture) lives
/// on the dedicated Welcome page, not in the store carousel. /// 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<TodayStoryData> _kFallbackTodayStories = <TodayStoryData>[ const List<TodayStoryData> _kFallbackTodayStories = <TodayStoryData>[
TodayStoryData( TodayStoryData(
badgeEn: 'MCP', badgeEn: 'MCP',
@ -3433,7 +3440,12 @@ class _StoreTodayHero extends StatelessWidget {
runSpacing: 4, runSpacing: 4,
crossAxisAlignment: WrapCrossAlignment.center, crossAxisAlignment: WrapCrossAlignment.center,
children: [ children: [
ChainPill(label: l.storeTodayBadge, tone: ChainPillTone.accent), ChainPill(
label: storeDeckIsAcceptedToday(totalCount)
? l.storeTodayBadge
: l.storeFeaturedBadge,
tone: ChainPillTone.accent,
),
Text( Text(
badge, badge,
style: theme.textTheme.labelSmall?.copyWith( style: theme.textTheme.labelSmall?.copyWith(

View file

@ -149,9 +149,12 @@ class ChainWorkspaceSwitcher extends StatelessWidget {
? l.workspaceSealedRunning ? l.workspaceSealedRunning
: l.workspaceSealedStopped, : l.workspaceSealedStopped,
style: theme.textTheme.labelSmall?.copyWith( style: theme.textTheme.labelSmall?.copyWith(
// Secondary but readable onSurfaceVariant
// fell below comfortable contrast at this
// size (usertest finding).
color: a.running color: a.running
? ChainColors.success ? ChainColors.success
: theme.colorScheme.onSurfaceVariant, : theme.colorScheme.onSurface.withValues(alpha: 0.8),
), ),
), ),
), ),

View file

@ -1,7 +1,7 @@
name: chain_studio name: chain_studio
description: "Ch∆In Studio — desktop GUI for the Ch∆In hub" description: "Ch∆In Studio — desktop GUI for the Ch∆In hub"
publish_to: 'none' publish_to: 'none'
version: 0.72.0 version: 0.72.1
environment: environment:
sdk: ^3.11.0-200.1.beta sdk: ^3.11.0-200.1.beta

View file

@ -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);
});
});
}