feat: full pattern matrix — M1 complete, M2 LLM chat, 30+ pattern files #10

Open
pyr0ball wants to merge 27 commits from feat/patterns-expansion into main
Owner

Summary

This branch completes M1 (log watching + pattern matching + tray notifications), wires M2 (Ollama streaming chat), and builds out the full migration pattern library.

  • M1 complete: journald, kmsg, and inotify app-log watchers; pattern classifier; tray badge + desktop toast; pending event queue with panel drain
  • M2 LLM chat: llm.rs streaming client against Ollama /api/chat; chat Tauri command; ChatPanel.vue streams tokens character-by-character
  • 30 pattern files: full matrix of source→target migrations across all major OS/distro combinations
  • Multi-step onboarding: source OS → source Linux distro (L-to-L) → dual-boot question

Pattern coverage

Source Targets
macOS arch
Windows debian
Linux (generic / experienced distro-hopper) arch
debian family arch, fedora, opensuse
fedora family arch, debian, opensuse
arch family debian, fedora, opensuse
opensuse family arch, debian, fedora
Android arch, debian, fedora, opensuse
iPad / iOS arch, debian, fedora, opensuse
Dual-boot supplement windows, macos

Android and iPad pattern files assume zero terminal experience — every command explained from first principles with App Store analogies.

Linux-to-Linux files are tuned to the reader's prior tooling: a Fedora user's arch patterns explain DNF analogues; an Arch user's debian patterns explain dpkg recovery and unattended-upgrades.

Dual-boot supplements (dualboot-windows.toml, dualboot-macos.toml) are layered on top of the primary pattern file via PatternFile::extend() when migration.dual_boot_with is set. Covers NTFS Fast Startup, clock skew, GRUB overwrite, BitLocker, T2 Secure Boot, APFS mounting.

New config fields

[migration]
source_os = "windows"          # now includes android, ipad
source_distro_family = "debian" # L-to-L routing
dual_boot_with = "windows"     # triggers supplement loading
distro = "linuxmint"
fluency_level = 0

Onboarding flow (3 steps)

  1. Source OS (Windows / macOS / Another Linux / Android / iPad)
  2. Source distro family — Linux-to-Linux only
  3. Dual-boot question — Windows/macOS only; mobile skips

Test plan

  • cargo test on a machine with webkit2gtk — Munnin (Linux Mint) is available
  • Onboarding: walk each source OS path, confirm correct TOML written to ~/.config/robin/config.toml
  • Pattern matching: trigger a known log line and confirm tray badge + toast appear
  • Windows-to-debian path on Munnin: set source_os = "windows" in config, confirm windows-to-debian.toml loads and NTFS/apt patterns fire correctly on a real Mint machine
  • Dual-boot supplement: set dual_boot_with = "windows", confirm dualboot-windows.toml patterns merge in
  • Chat: with Ollama running (ollama serve), send a message and confirm tokens stream into chat panel
  • Mobile path: set source_os = "android", confirm beginner-friendly pattern bodies appear

Closes #1 (M1 foundation), closes #2 (M2 LLM chat). Relates to #3 (pattern expansion), #4 (Linux-to-Linux paths), #7 (onboarding).

## Summary This branch completes M1 (log watching + pattern matching + tray notifications), wires M2 (Ollama streaming chat), and builds out the full migration pattern library. - **M1 complete**: journald, kmsg, and inotify app-log watchers; pattern classifier; tray badge + desktop toast; pending event queue with panel drain - **M2 LLM chat**: `llm.rs` streaming client against Ollama `/api/chat`; `chat` Tauri command; `ChatPanel.vue` streams tokens character-by-character - **30 pattern files**: full matrix of source→target migrations across all major OS/distro combinations - **Multi-step onboarding**: source OS → source Linux distro (L-to-L) → dual-boot question ## Pattern coverage | Source | Targets | |--------|---------| | macOS | arch | | Windows | debian | | Linux (generic / experienced distro-hopper) | arch | | debian family | arch, fedora, opensuse | | fedora family | arch, debian, opensuse | | arch family | debian, fedora, opensuse | | opensuse family | arch, debian, fedora | | Android | arch, debian, fedora, opensuse | | iPad / iOS | arch, debian, fedora, opensuse | | Dual-boot supplement | windows, macos | Android and iPad pattern files assume zero terminal experience — every command explained from first principles with App Store analogies. Linux-to-Linux files are tuned to the reader's prior tooling: a Fedora user's arch patterns explain DNF analogues; an Arch user's debian patterns explain dpkg recovery and unattended-upgrades. Dual-boot supplements (`dualboot-windows.toml`, `dualboot-macos.toml`) are layered on top of the primary pattern file via `PatternFile::extend()` when `migration.dual_boot_with` is set. Covers NTFS Fast Startup, clock skew, GRUB overwrite, BitLocker, T2 Secure Boot, APFS mounting. ## New config fields ```toml [migration] source_os = "windows" # now includes android, ipad source_distro_family = "debian" # L-to-L routing dual_boot_with = "windows" # triggers supplement loading distro = "linuxmint" fluency_level = 0 ``` ## Onboarding flow (3 steps) 1. Source OS (Windows / macOS / Another Linux / Android / iPad) 2. Source distro family — Linux-to-Linux only 3. Dual-boot question — Windows/macOS only; mobile skips ## Test plan - [ ] `cargo test` on a machine with webkit2gtk — Munnin (Linux Mint) is available - [ ] Onboarding: walk each source OS path, confirm correct TOML written to `~/.config/robin/config.toml` - [ ] Pattern matching: trigger a known log line and confirm tray badge + toast appear - [ ] **Windows-to-debian path on Munnin**: set `source_os = "windows"` in config, confirm `windows-to-debian.toml` loads and NTFS/apt patterns fire correctly on a real Mint machine - [ ] Dual-boot supplement: set `dual_boot_with = "windows"`, confirm `dualboot-windows.toml` patterns merge in - [ ] Chat: with Ollama running (`ollama serve`), send a message and confirm tokens stream into chat panel - [ ] Mobile path: set `source_os = "android"`, confirm beginner-friendly pattern bodies appear ## Related issues Closes #1 (M1 foundation), closes #2 (M2 LLM chat). Relates to #3 (pattern expansion), #4 (Linux-to-Linux paths), #7 (onboarding).
pyr0ball added 25 commits 2026-05-19 10:45:37 -07:00
- parse_id now strips both double and single quotes per os-release spec
- distro_family debian arm includes "mint" (legacy Linux Mint ID)
- Add tests: single-quoted ID round-trip, mint family classification
Add EventSource enum and update SystemEvent in watcher.rs (M0 stub
updated to support Task 5 clean deletion). Create patterns.rs with
PatternFile/Pattern/MatchedEvent types, TOML loader, and classify()
matching against source + text. Five unit tests covering journald,
applog, no-match, and source discrimination cases.
- load() now rejects patterns with empty match_text or empty sources list
- EventSource derives Serialize/Deserialize with serde tag for emit() readiness
- AppLog variant changed to struct form (AppLog { app }) for tagged enum compat
- classify() takes &SystemEvent directly (top-level use import, not per-fn)
- #[must_use] on classify()
- 5 new tests: any-source wildcard (journald+kmsg), applog mismatch, empty-field validation
Replace flat watcher.rs with watcher/ module containing mod.rs plus stub
sub-modules for journald, kmsg, and inotify. Upgrades spawn() to accept
log_paths and return mpsc::Receiver<SystemEvent>. Updates lib.rs call site.
- read_to_end + from_utf8_lossy replaces read_to_string so Wine/game logs
  with Latin-1 bytes are handled via U+FFFD replacement instead of silently
  dropping all events from that file
- bytes_read from I/O call used for new_pos (not content.len()) for correct
  byte position accounting
- spawn_blocking handle is now awaited so panics inside the blocking task
  surface to the caller instead of being silently swallowed
- lib.rs: replaces stub setup with full wiring: loads PatternFile from
  config, extracts log_paths, spawns watcher, runs classifier loop in
  async task, dispatches MatchedEvents via notify::dispatch
- lib.rs: config Mutex lock uses unwrap_or_else(|e| e.into_inner()) to
  recover from poison instead of panicking
- patterns.rs: load() now tries three path candidates in order
  (dev-relative, src-tauri-relative, system) before returning bail!
  Validation loop (match_text, sources) retained inside candidate loop
macOS-to-Arch: +9 patterns (pacman lock, dep conflict, DKMS build fail,
PipeWire, WirePlumber, Bluetooth rfkill/profile, GPU hang, XWayland crash,
OOM killer, disk I/O, NetworkManager)

Windows-to-Debian: +11 patterns (dpkg interrupted, PipeWire, PulseAudio,
Bluetooth rfkill/profile, NTFS dirty/force flags, disk I/O, USB reset,
OOM killer, GPU hang, NetworkManager, CUPS unavailable)

All patterns target sources Robin actually watches: journald, kmsg, applog.
match_text strings use invariant substrings from real log output.
Targets an experienced Debian/Fedora user on first Arch install. Body text
is terse and technical — no hand-holding, just Arch-specific gotchas.

- pacman.log as watched applog source (catches terminal pacman/AUR runs)
- pacman/AUR: db lock, dep conflicts, conflicting files, build failures,
  PGP keys, missing makedepends, partial upgrade warning, Chaotic-AUR sig
- DKMS: build failures + CachyOS kernel module signature mismatch
- System: locale not generated (Arch vs Debian difference), systemd-resolved,
  OOM (zram suggestion), disk I/O
- Audio: PipeWire/WirePlumber, Bluetooth rfkill + profile
- GPU: hang (mesa-git/DKMS version mismatch context), XWayland crash
- Gaming: Proton, Lutris Wine runner
- Network: NetworkManager + Realtek firmware callout for CachyOS
Pattern files: 12 cross-family migration pairs covering debian, fedora, arch,
opensuse — each tuned to the user's prior tooling (apt, dnf, pacman, zypper).
Includes the custom linux-to-arch file for experienced distro-hoppers and
the macos-to-arch / windows-to-debian expansions from the prior session.

Code changes:
- patterns::load() accepts source_distro_family: Option<&str> — tries
  specific debian-to-arch.toml before falling back to linux-to-arch.toml
- MigrationConfig adds source_distro_family: Option<String> with serde default
- complete_onboarding() accepts optional source_distro arg and derives family
  via distro_family() for Linux-to-Linux migrations
- llm.rs: Ollama streaming client with Vec<u8> buffer for UTF-8 safety,
  emit errors logged not silenced
- commands::chat: spawns stream task, returns immediately so frontend
  isn't blocked waiting for full LLM response
- lib.rs: registers mod llm and commands::chat in invoke_handler
New SourceOs variants: Android, IpadOs — routed to android-to-* and
ipad-to-* pattern files respectively. Pattern bodies assume zero terminal
experience; every command explained from first principles with App Store /
iOS analogies.

Dual-boot supplement system: PatternFile::extend() + load_supplement()
in patterns.rs; lib.rs loads dualboot-{windows,macos}.toml on top of the
primary pattern file when migration.dual_boot_with is set. Supplement
covers NTFS dirty flag from Fast Startup, clock skew (RTC local vs UTC),
GRUB overwrite by Windows Update, BitLocker, APFS/HFS+ access, T2 Secure
Boot.

complete_onboarding() now accepts dual_boot_with: Option<String> and
normalises it to "windows"/"macos". Onboarding.vue becomes a 3-step flow:
source OS -> (Linux distro if linux) -> (dual-boot if windows/macos).
Mobile users skip the dual-boot step entirely.

10 new pattern files (8 mobile + 2 supplements), config.rs tests updated.
pyr0ball added 1 commit 2026-05-20 08:32:48 -07:00
- Add reqwest 0.12 (json + stream features) — was missing from Cargo.toml
  causing chat_stream to fail to compile
- Add Android/IpadOs arms to SourceOs match in chat command
- Add tauri::Manager import to notify.rs (needed for .state())
- Replace deprecated menu_on_left_click with show_menu_on_left_click
- Remove desktopTemplate from tauri.conf.json (not in tauri-utils 2.9.2 schema)
- Commit Cargo.lock so cross-machine builds pin identical crate versions

All 42 unit tests pass on Linux Mint 22.3 (Muninn).
pyr0ball added 1 commit 2026-05-20 09:59:46 -07:00
- Fix main.rs: app_lib crate name was wrong, should be robin_lib
- Add log::info! on pattern load success/failure — startup was completely
  silent making smoke testing and production diagnosis impossible
- Log pattern count and dual-boot supplement count on load
- Log matched pattern id on every notification dispatch
- These messages appear in ~/.local/share/tech.circuitforge.robin/logs/Robin.log
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/patterns-expansion:feat/patterns-expansion
git checkout feat/patterns-expansion

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git checkout main
git merge --no-ff feat/patterns-expansion
git checkout feat/patterns-expansion
git rebase main
git checkout main
git merge --ff-only feat/patterns-expansion
git checkout feat/patterns-expansion
git rebase main
git checkout main
git merge --no-ff feat/patterns-expansion
git checkout main
git merge --squash feat/patterns-expansion
git checkout main
git merge --ff-only feat/patterns-expansion
git checkout main
git merge feat/patterns-expansion
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Circuit-Forge/robin#10
No description provided.