Anti-patterns

Concrete ❌ vs ✅ pairs for the failure modes we keep seeing in code review. Each card links to the spec that governs the right answer; the explanation says why the wrong one bites.

Anti-patterns

Title-bar gesture arena hijack

Desktop

specs/desktop-apps/title-bar-double-click.kmd

Don't Wraps the whole bar with onDoubleTap + onPanStart.
// ❌ Wraps the whole title bar — hijacks the gesture arena.
GestureDetector(
  onDoubleTap: () => windowManager.maximize(),
  onPanStart: (_) => windowManager.startDragging(),
  child: TitleBarRow(...),
)
Do Drag is implicit; double-tap scoped to free area.
// ✅ Drag is implicit; double-tap is scoped to the free area.
KoderTitleBar(
  title: 'My App',
  trailing: [KoderTitleBarFreeArea()],
)

Why: GestureDetector at the top of the bar wins the gesture arena even over child buttons. Users tap close, the window maximizes instead. KoderTitleBar handles drag and double-tap with the right scopes.

Hardcoded UI strings

i18n

specs/i18n/contract.kmd

Don't Plain string literal — never reaches the locale pipeline.
// ❌ One language; never reaches the ICU pipeline.
Text('Sign in to continue')
Do ICU key lookup with en-US baseline + pt-BR mandatory.
// ✅ Backed by ICU keys with en-US baseline + pt-BR mandatory.
Text(KoderL10n.of(context).t('auth.gate.title'))

Why: Hardcoded strings are invisible to translators, to the locale switcher, and to /k-housekeep. They fossilize as English forever.

Hand-rolled error telemetry

Errors

specs/errors/reporting.kmd

Don't Local box / file / API; no consent gate.
// ❌ Custom storage; no consent gate; never reaches the reporter.
final box = await Hive.openBox('errors');
await box.add({'msg': error.toString(), 'time': DateTime.now()});
Do KoderErrorReporter with explicit consent.
// ✅ Consent-gated, anonymized, queues offline, ships to foundation/reporter.
KoderErrorReporter.configure(
  endpoint: Uri.parse('https://reporter.koder.dev/v1/events'),
  consentDefault: false,
);
await KoderErrorReporter.report(error: caughtError);

Why: Local stores leak with the device, miss the consent toggle, and never feed services/foundation/reporter. The reporter handles batching, anonymization, and offline queues.

Scaffold without window insets

Layout

specs/app-layout/safe-area.kmd

Don't Plain Scaffold; status bar overlaps content.
// ❌ Status bar / gesture bar overlap user content.
Scaffold(
  body: ListView(children: items),
)
Do KoderSafeScaffold respects every platform inset.
// ✅ Window insets respected on every surface.
KoderSafeScaffold(
  body: ListView(children: items),
)

Why: Notches, gesture bars, desktop chrome, and CSS env(safe-area-inset-*) all need to be honored. KoderSafeScaffold abstracts the platform differences.

Local login form against Flow

Auth

specs/koder-app/behaviors.kmd

Don't TextField for password; bypasses Koder ID.
// ❌ Password handled locally; bypasses Koder ID + OIDC PKCE.
Form(
  child: Column(children: [
    TextField(controller: usernameCtrl),
    TextField(controller: passwordCtrl, obscureText: true),
    ElevatedButton(onPressed: () => api.login(usernameCtrl.text, passwordCtrl.text), ...),
  ]),
)
Do KoderSignInButton delegates to OIDC PKCE.
// ✅ Delegates to Koder ID; PKCE + state validation handled by the SDK.
KoderSignInButton(
  redirectUri: 'kall://auth/callback',
  onSuccess: (user) => Navigator.of(context).pushReplacement(...),
)

Why: Per RFC-006 every Koder app authenticates through Koder ID. Local forms cannot do PKCE, cannot honor 2FA / passkeys, and re-implement timing-safe lookup poorly.

ThemeMode hardcoded before preference load

Theme

specs/themes/light-dark.kmd

Don't Forces dark on every cold start.
// ❌ Forces dark on every cold start; flash of wrong theme on devices
// where the user picked light.
return MaterialApp(
  themeMode: ThemeMode.dark,
  ...
);
Do Resolve from saved preference; fall back to ThemeMode.system.
// ✅ Reads SharedPreferences before runApp; falls back to ThemeMode.system.
ThemeMode _resolve(String? saved) {
  if (saved == 'dark') return ThemeMode.dark;
  if (saved == 'light') return ThemeMode.light;
  return ThemeMode.system;
}

Why: Hard-setting a mode causes the flash of wrong theme and ignores the user's earlier choice. Read SharedPreferences in main() before runApp.

Back behavior reinvented per screen

Navigation

specs/navigation/back-behavior.kmd

Don't Each screen ships its own WillPopScope.
// ❌ Each screen invents its own back rule. Two pops, tab switch on
// back, "are you sure?" on every back — pick your favourite bug.
WillPopScope(
  onWillPop: () async {
    if (somethingDirty) return await _showConfirm();
    Navigator.of(context).pop();
    return false;
  },
  child: ChildScreen(),
)
Do KoderBackScope at the root.
// ✅ Single source of truth — the SDK handles back/Esc consistently.
KoderBackScope(
  enableSystemExitAtRoot: true,
  child: HomeScreen(),
)

Why: Per-screen logic drifts: two pops, tab switch on back, exit only sometimes. Users can't predict what back does. KoderBackScope centralizes the rule per RFC.

Pre-wake buffer streamed to server

Voice

specs/voice/wake-word.kmd

Don't Audio uploaded continuously.
// ❌ Streams the pre-wake ring buffer to the server. Privacy contract
// violated; the buffer must never leave the device.
audioStream.listen((chunk) {
  api.uploadAudio(chunk);
});
Do Pre-wake stays local; only post-wake ships.
// ✅ Pre-wake stays local; only post-wake intent is shipped — and only
// if the user has explicitly enabled voice in Settings.
final wake = await KoderWakeWord.standby(); // local ring buffer
final intent = await KoderTalkMode.capture(); // shipped only after wake
api.handleIntent(intent);

Why: specs/voice/wake-word.kmd makes the pre-wake ring buffer strictly local. Streaming it violates the privacy contract and the user's consent.

Language switch via full reload

i18n

specs/i18n/contract.kmd

Don't window.location.reload() drops scroll + form state.
// ❌ Full page reload kills scroll position and form state.
function setLocale(loc) {
  document.cookie = 'locale=' + loc;
  window.location.reload();
}
Do ICU subscription; consumers rebuild in place.
// ✅ ICU subscription rebuilds string consumers in place.
import { koderL10n } from 'koder-web-kit';
function setLocale(loc) {
  koderL10n.set(loc); // persists + notifies subscribers
}

Why: Reload feels like a bug to the user. The locale change should be observable; consumers update without losing context.

Non-canonical app subdomain

URL

specs/landing-pages/products.kmd

Don't app.<produto>.koder.dev — breaks OAuth callbacks.
<!-- ❌ Non-canonical host. OAuth callbacks registered for
     <produto>.koder.dev now break. -->
<a href="https://app.kall.koder.dev/">Open the app</a>
Do <produto>.koder.dev — canonical.
<!-- ✅ Canonical product URL. /about hosts the marketing landing
     page; /auth/callback is the OIDC redirect target. -->
<a href="https://kall.koder.dev/">Open the app</a>

Why: Every OAuth callback registered for the canonical host fails on the app.* variant. specs/landing-pages/products.kmd §URL pins the canonical host.

Access token in localStorage

Storage

specs/koder-app/behaviors.kmd

Don't Any same-origin script can read it.
// ❌ Access token in localStorage. Any same-origin script can read it;
// shared devices leak it across users.
localStorage.setItem('token', accessToken);
Do Platform secure store (KeyStore / Keychain / libsecret).
// ✅ Platform secure store (KeyStore on Android, Keychain on iOS,
// libsecret on Linux, IndexedDB+WebCrypto wrapper on web).
import { koderSecureStore } from 'koder-web-kit';
await koderSecureStore.set('token', accessToken);

Why: Shared devices and XSS get cross-user token reads. The secure store is the only place that survives every threat model.

Hardcoded viewport / inset values

Layout

specs/app-layout/safe-area.kmd

Don't Pixel widths and pixel paddings.
/* ❌ Fixed pixel sizes break multi-monitor with mixed DPI and ignore
   the safe-area insets. */
.app {
  width: 1280px;
  padding-top: 24px;   /* status bar height ??? */
  padding-bottom: 24px;
}
Do max-width 100vw + env(safe-area-inset-*) padding.
/* ✅ Responsive + insets. Same code works on phone, desktop, and PWA. */
.app {
  max-width: 100vw;
  padding-top:    max(env(safe-area-inset-top),    1rem);
  padding-bottom: max(env(safe-area-inset-bottom), 1rem);
}

Why: Multi-monitor with mixed DPI breaks pixel math. The CSS environment variables expose the actual safe area without guessing.