frosty/AGENTS.md

47 lines
3.2 KiB
Markdown
Raw Normal View History

2026-01-11 16:59:33 -08:00
# AGENTS.md
Flutter Twitch client for iOS and Android. MobX with `build_runner`. The landing page is `web/` (own `AGENTS.md`). Flutter is pinned in `pubspec.yaml` `environment.flutter` — bump that one field; CI reads it via `flutter-version-file`.
2026-01-11 16:59:33 -08:00
migrate web to next 16 template and redesign landing page (#526) * migrate web to next-template stack (next 16, react 19, tailwind 4) replace all infrastructure with next-template conventions: - next.js 14 -> 16 (turbopack default, typed routes, react compiler) - react 18 -> 19 - tailwind css 3 -> 4 (css-first config, oklch theme system) - eslint 8 (.eslintrc) -> 9 (flat config with stricter rules) - add shadcn/ui, base-ui, cva component primitives - upgrade theme toggle to light/dark/system dropdown - migrate hardcoded neutral classes to semantic oklch tokens - drop unused @tailwindcss/forms, autoprefixer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add no-misused-promises config for async JSX handlers, warn on array index keys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * base-vega * sync frosty web with next-template runtime and claude tooling for cloudflare parity * gitignore .dev.vars per cloudflare best practice Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add observability configuration to wrangler.jsonc * remove marquee emote background from hero section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * improve CLAUDE.md and AGENTS.md files across project Remove redundant root CLAUDE.md (kept in .claude/ instead), add Commands and Source Structure sections to Flutter AGENTS.md, clarify global vs feature store placement, and fill gaps in web AGENTS.md (shadcn base-vega style, constants.ts, no-array-index-key rule, commit conventions). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * switch shadcn theme from neutral to violet, replace twitch-purple with primary token Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * initial redesign * auto-infer nativeButton in Button wrapper when render prop is used Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * replace skeleton carousel with real screenshots and video, add responsive phone scaling and mobile menu - Replace PhoneSkeleton with PhoneFrame/PhoneMedia using actual app screenshots and video - Fluid phone sizing via aspect-ratio with responsive max-h/max-w caps - Non-circular carousel with swipe gestures, dot indicator, and hover opacity boost - Video plays only when focused, pauses when off-screen - Collapse header actions into dropdown menu on mobile, add Contact link - Viewport-height layout with no scrolling on any screen size - Remove footer, move contact to header Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * improve header consistency, carousel layout, and responsive centering - add icons to all header buttons (Contact, Donate, GitHub) - switch theme toggle to ghost variant for consistency - bump header collapse breakpoint from md to lg - move carousel arrows to overlay positions with animated enter/exit - hide arrows at first/last slide - fix vertical centering of phone+description group across all screen sizes - add smooth blur+slide transition for description text Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add contact dropdown with copy email toast - replace direct mailto link with dropdown: send email or copy email - install sonner for toast notifications, show top-center on copy - extract emailAddress constant for clipboard use - add copy option to mobile hamburger menu too Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * replace mobile hamburger menu with icon buttons Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * redesign hero copy, badge-style download buttons, and mobile layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add consistent padding and object-contain to carousel media Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add emote physics background to hero section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * move container styling to hero panel, refresh emote set with 2025 trending picks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add staggered entrance animations and remove grid gap Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add 30-day cache headers for video and logo assets Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add emote collisions and aspect-ratio tracking, refine hero layout Emote physics: add particle-particle elastic collisions, per-particle width measurement for correct aspect ratios, new emotes (aga, WW, o7, FLASHBANG, LULW, Deadass), bump count to 30. Layout: absolute-position header with z-20, increase mobile carousel ratio to 2fr/4fr, reserve min-h-10 for description text, remove panel rounding. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix carousel lint warnings: useSyncExternalStore, ref naming, stable keys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add seo metadata, sitemap, and robots.txt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add privacy link to header and footer credit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * update privacy policy content and restyle with mono layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * reorder header nav and add mobile hamburger menu Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refresh web dependencies and smooth footer credit hover transition --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:53:43 -05:00
## Commands
```bash
flutter pub get
flutter run --dart-define-from-file=.env # local; .env is gitignored
flutter run --dart-define=CLIENT_ID=ID --dart-define=SECRET=SECRET
flutter analyze
flutter test
flutter test test/path/to/file.dart
dart run build_runner build # after MobX / @JsonSerializable changes
migrate web to next 16 template and redesign landing page (#526) * migrate web to next-template stack (next 16, react 19, tailwind 4) replace all infrastructure with next-template conventions: - next.js 14 -> 16 (turbopack default, typed routes, react compiler) - react 18 -> 19 - tailwind css 3 -> 4 (css-first config, oklch theme system) - eslint 8 (.eslintrc) -> 9 (flat config with stricter rules) - add shadcn/ui, base-ui, cva component primitives - upgrade theme toggle to light/dark/system dropdown - migrate hardcoded neutral classes to semantic oklch tokens - drop unused @tailwindcss/forms, autoprefixer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add no-misused-promises config for async JSX handlers, warn on array index keys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * base-vega * sync frosty web with next-template runtime and claude tooling for cloudflare parity * gitignore .dev.vars per cloudflare best practice Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add observability configuration to wrangler.jsonc * remove marquee emote background from hero section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * improve CLAUDE.md and AGENTS.md files across project Remove redundant root CLAUDE.md (kept in .claude/ instead), add Commands and Source Structure sections to Flutter AGENTS.md, clarify global vs feature store placement, and fill gaps in web AGENTS.md (shadcn base-vega style, constants.ts, no-array-index-key rule, commit conventions). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * switch shadcn theme from neutral to violet, replace twitch-purple with primary token Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * initial redesign * auto-infer nativeButton in Button wrapper when render prop is used Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * replace skeleton carousel with real screenshots and video, add responsive phone scaling and mobile menu - Replace PhoneSkeleton with PhoneFrame/PhoneMedia using actual app screenshots and video - Fluid phone sizing via aspect-ratio with responsive max-h/max-w caps - Non-circular carousel with swipe gestures, dot indicator, and hover opacity boost - Video plays only when focused, pauses when off-screen - Collapse header actions into dropdown menu on mobile, add Contact link - Viewport-height layout with no scrolling on any screen size - Remove footer, move contact to header Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * improve header consistency, carousel layout, and responsive centering - add icons to all header buttons (Contact, Donate, GitHub) - switch theme toggle to ghost variant for consistency - bump header collapse breakpoint from md to lg - move carousel arrows to overlay positions with animated enter/exit - hide arrows at first/last slide - fix vertical centering of phone+description group across all screen sizes - add smooth blur+slide transition for description text Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add contact dropdown with copy email toast - replace direct mailto link with dropdown: send email or copy email - install sonner for toast notifications, show top-center on copy - extract emailAddress constant for clipboard use - add copy option to mobile hamburger menu too Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * replace mobile hamburger menu with icon buttons Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * redesign hero copy, badge-style download buttons, and mobile layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add consistent padding and object-contain to carousel media Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add emote physics background to hero section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * move container styling to hero panel, refresh emote set with 2025 trending picks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add staggered entrance animations and remove grid gap Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add 30-day cache headers for video and logo assets Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add emote collisions and aspect-ratio tracking, refine hero layout Emote physics: add particle-particle elastic collisions, per-particle width measurement for correct aspect ratios, new emotes (aga, WW, o7, FLASHBANG, LULW, Deadass), bump count to 30. Layout: absolute-position header with z-20, increase mobile carousel ratio to 2fr/4fr, reserve min-h-10 for description text, remove panel rounding. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix carousel lint warnings: useSyncExternalStore, ref naming, stable keys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add seo metadata, sitemap, and robots.txt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add privacy link to header and footer credit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * update privacy policy content and restyle with mono layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * reorder header nav and add mobile hamburger menu Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refresh web dependencies and smooth footer credit hover transition --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:53:43 -05:00
```
`--delete-conflicting-outputs` is ignored as of build_runner 2.15. Don't add it.
## Layout
migrate web to next 16 template and redesign landing page (#526) * migrate web to next-template stack (next 16, react 19, tailwind 4) replace all infrastructure with next-template conventions: - next.js 14 -> 16 (turbopack default, typed routes, react compiler) - react 18 -> 19 - tailwind css 3 -> 4 (css-first config, oklch theme system) - eslint 8 (.eslintrc) -> 9 (flat config with stricter rules) - add shadcn/ui, base-ui, cva component primitives - upgrade theme toggle to light/dark/system dropdown - migrate hardcoded neutral classes to semantic oklch tokens - drop unused @tailwindcss/forms, autoprefixer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add no-misused-promises config for async JSX handlers, warn on array index keys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * base-vega * sync frosty web with next-template runtime and claude tooling for cloudflare parity * gitignore .dev.vars per cloudflare best practice Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add observability configuration to wrangler.jsonc * remove marquee emote background from hero section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * improve CLAUDE.md and AGENTS.md files across project Remove redundant root CLAUDE.md (kept in .claude/ instead), add Commands and Source Structure sections to Flutter AGENTS.md, clarify global vs feature store placement, and fill gaps in web AGENTS.md (shadcn base-vega style, constants.ts, no-array-index-key rule, commit conventions). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * switch shadcn theme from neutral to violet, replace twitch-purple with primary token Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * initial redesign * auto-infer nativeButton in Button wrapper when render prop is used Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * replace skeleton carousel with real screenshots and video, add responsive phone scaling and mobile menu - Replace PhoneSkeleton with PhoneFrame/PhoneMedia using actual app screenshots and video - Fluid phone sizing via aspect-ratio with responsive max-h/max-w caps - Non-circular carousel with swipe gestures, dot indicator, and hover opacity boost - Video plays only when focused, pauses when off-screen - Collapse header actions into dropdown menu on mobile, add Contact link - Viewport-height layout with no scrolling on any screen size - Remove footer, move contact to header Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * improve header consistency, carousel layout, and responsive centering - add icons to all header buttons (Contact, Donate, GitHub) - switch theme toggle to ghost variant for consistency - bump header collapse breakpoint from md to lg - move carousel arrows to overlay positions with animated enter/exit - hide arrows at first/last slide - fix vertical centering of phone+description group across all screen sizes - add smooth blur+slide transition for description text Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add contact dropdown with copy email toast - replace direct mailto link with dropdown: send email or copy email - install sonner for toast notifications, show top-center on copy - extract emailAddress constant for clipboard use - add copy option to mobile hamburger menu too Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * replace mobile hamburger menu with icon buttons Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * redesign hero copy, badge-style download buttons, and mobile layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add consistent padding and object-contain to carousel media Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add emote physics background to hero section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * move container styling to hero panel, refresh emote set with 2025 trending picks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add staggered entrance animations and remove grid gap Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add 30-day cache headers for video and logo assets Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add emote collisions and aspect-ratio tracking, refine hero layout Emote physics: add particle-particle elastic collisions, per-particle width measurement for correct aspect ratios, new emotes (aga, WW, o7, FLASHBANG, LULW, Deadass), bump count to 30. Layout: absolute-position header with z-20, increase mobile carousel ratio to 2fr/4fr, reserve min-h-10 for description text, remove panel rounding. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix carousel lint warnings: useSyncExternalStore, ref naming, stable keys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add seo metadata, sitemap, and robots.txt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add privacy link to header and footer credit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * update privacy policy content and restyle with mono layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * reorder header nav and add mobile hamburger menu Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refresh web dependencies and smooth footer credit hover transition --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:53:43 -05:00
- `lib/apis/` — API clients extend `BaseApiClient`
- `lib/models/` — data models; `@JsonSerializable` ones commit `.g.dart`
- `lib/screens/{feature}/` — screens; feature stores in co-located `stores/`
- `lib/stores/` — global stores only (`global_assets_store.dart`)
- `test/` mirrors `lib/`; shared fixtures in `test/fixtures/`
migrate web to next 16 template and redesign landing page (#526) * migrate web to next-template stack (next 16, react 19, tailwind 4) replace all infrastructure with next-template conventions: - next.js 14 -> 16 (turbopack default, typed routes, react compiler) - react 18 -> 19 - tailwind css 3 -> 4 (css-first config, oklch theme system) - eslint 8 (.eslintrc) -> 9 (flat config with stricter rules) - add shadcn/ui, base-ui, cva component primitives - upgrade theme toggle to light/dark/system dropdown - migrate hardcoded neutral classes to semantic oklch tokens - drop unused @tailwindcss/forms, autoprefixer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add no-misused-promises config for async JSX handlers, warn on array index keys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * base-vega * sync frosty web with next-template runtime and claude tooling for cloudflare parity * gitignore .dev.vars per cloudflare best practice Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add observability configuration to wrangler.jsonc * remove marquee emote background from hero section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * improve CLAUDE.md and AGENTS.md files across project Remove redundant root CLAUDE.md (kept in .claude/ instead), add Commands and Source Structure sections to Flutter AGENTS.md, clarify global vs feature store placement, and fill gaps in web AGENTS.md (shadcn base-vega style, constants.ts, no-array-index-key rule, commit conventions). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * switch shadcn theme from neutral to violet, replace twitch-purple with primary token Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * initial redesign * auto-infer nativeButton in Button wrapper when render prop is used Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * replace skeleton carousel with real screenshots and video, add responsive phone scaling and mobile menu - Replace PhoneSkeleton with PhoneFrame/PhoneMedia using actual app screenshots and video - Fluid phone sizing via aspect-ratio with responsive max-h/max-w caps - Non-circular carousel with swipe gestures, dot indicator, and hover opacity boost - Video plays only when focused, pauses when off-screen - Collapse header actions into dropdown menu on mobile, add Contact link - Viewport-height layout with no scrolling on any screen size - Remove footer, move contact to header Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * improve header consistency, carousel layout, and responsive centering - add icons to all header buttons (Contact, Donate, GitHub) - switch theme toggle to ghost variant for consistency - bump header collapse breakpoint from md to lg - move carousel arrows to overlay positions with animated enter/exit - hide arrows at first/last slide - fix vertical centering of phone+description group across all screen sizes - add smooth blur+slide transition for description text Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add contact dropdown with copy email toast - replace direct mailto link with dropdown: send email or copy email - install sonner for toast notifications, show top-center on copy - extract emailAddress constant for clipboard use - add copy option to mobile hamburger menu too Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * replace mobile hamburger menu with icon buttons Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * redesign hero copy, badge-style download buttons, and mobile layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add consistent padding and object-contain to carousel media Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add emote physics background to hero section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * move container styling to hero panel, refresh emote set with 2025 trending picks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add staggered entrance animations and remove grid gap Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add 30-day cache headers for video and logo assets Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add emote collisions and aspect-ratio tracking, refine hero layout Emote physics: add particle-particle elastic collisions, per-particle width measurement for correct aspect ratios, new emotes (aga, WW, o7, FLASHBANG, LULW, Deadass), bump count to 30. Layout: absolute-position header with z-20, increase mobile carousel ratio to 2fr/4fr, reserve min-h-10 for description text, remove panel rounding. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix carousel lint warnings: useSyncExternalStore, ref naming, stable keys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add seo metadata, sitemap, and robots.txt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add privacy link to header and footer credit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * update privacy policy content and restyle with mono layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * reorder header nav and add mobile hamburger menu Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refresh web dependencies and smooth footer credit hover transition --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:53:43 -05:00
Don't add top-level store files or standalone API classes. Canonical MobX store: `lib/screens/settings/stores/auth_store.dart`. Extract state, reactions, and actions into stores when it keeps widgets on rendering.
2026-01-11 16:59:33 -08:00
New or changed logic (stores, API clients, parsing, utils) ships with tests; extend existing tests when touching tested code. Pure UI or config may skip. HTTP: `http_mock_adapter` (`DioAdapter`) with full URLs. Otherwise `mocktail`.
2026-02-07 01:02:47 -08:00
## Gotchas
2026-02-07 00:46:01 -08:00
- Commit regenerated `.g.dart` files. Never edit them. CI fails the PR if they're stale.
- `main.dart` secure-storage `deleteAll()` looks redundant; it handles Android/iOS storage surviving uninstall. Don't remove it.
- `flutter_secure_storage` stays on v9 (v10 shipped in 5.0.0 and was reverted in 5.0.1 over an Android 14 startup freeze). That also holds `package_info_plus` v9 and `device_info_plus` v12 (win32). Don't jump them in a drive-by upgrade.
- Git-pinned forks in `pubspec.yaml` (`extended_text_field`, `better_native_video_player`, `simple_pip_mode`) carry patches. Don't swap them back to pub.dev.
- `android/gradle.properties`: keep `android.builtInKotlin=false` and `android.newDsl=false` so plugins that still apply KGP build on AGP 9.
- `ios/Runner/AppDelegate.swift` is customized (`CookieExtractorPlugin` + `FlutterImplicitEngineDelegate`). Flutter will not auto-migrate UIScene; don't replace the delegate with the template.
- `android/.../MainActivity.kt` extends `PipCallbackHelperActivityWrapper` and registers `CookieExtractorPlugin` by hand. Don't revert it to `FlutterActivity`.
- Helix OAuth (`Bearer`) and the Twitch web GQL cookie are different tokens. Native playback uses the cookie; don't send the Helix token to GQL/Usher.
- `syncedChatDelay` is runtime-only (`includeFromJson/toJson: false`). Don't persist it with the other settings.
- Don't remove the `ALLOW_DEBUG_SIGNED_RELEASE` branch in `android/app/build.gradle.kts`. Real releases must still fail if `key.properties` is missing.
2026-01-11 16:59:33 -08:00
## Releases
When cutting a store or GitHub release, read `docs/release.md` and follow it. That playbook is repo-local, not a global skill. `assets/release-notes.md` keeps about three consecutive versions; drop from the oldest end, never skip.