Some checks failed
Check / eval (push) Has been cancelled
Add a "Fanning out worktree agents" subsection to §6.5: match model to
task (sonnet for spec'd work, opus for judgment), point briefs at the
backlog spec, disjoint file lanes, worktree isolation with the parent
owning landing, lean on scriptable checks as evidence, batch V2 in one
VM pass. First commit of the tracked skill (skills were un-ignored in
7d52d4b). MEMORY note updated: skills are now tracked.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
118 lines
7.0 KiB
Markdown
118 lines
7.0 KiB
Markdown
# Memory — durable lessons, learned the hard way
|
|
|
|
Curated, not append-only: one line per fact, newest at the top of its
|
|
section; delete entries that stop being true. Details usually live in a
|
|
docs/ROADMAP.md decision record — pointer given as (§ item). Add a fact
|
|
here the moment a debugging session teaches you something a future
|
|
iteration would otherwise rediscover.
|
|
|
|
## Testing & VM recipes
|
|
- **tuigreet dies silently under runNixOSTest** (even bare, no theme
|
|
flag: greetd sits as "(greetd)" with no child, nothing in the
|
|
journal — its stderr goes to the VT) — nixpkgs' own greetd test uses
|
|
agreety instead. Greeter *rendering* is interactive-ISO/hardware
|
|
tier; don't burn another session on a checks.greeter VM test.
|
|
- In VM tests `pgrep -f PATTERN` can match the test backdoor's own
|
|
`bash -c` wrapper (the pattern is in its cmdline) — use `pgrep -x`
|
|
or a `[t]uigreet`-style bracket pattern.
|
|
- A checks.* fixture CANNOT be a writeText/toFile state file read at
|
|
eval time ("path … is not valid" — flake check's eval store won't
|
|
realise it): extract the logic into a pure importable file and
|
|
unit-test THAT (monitor-rules.nix / checks.display-profiles is the
|
|
pattern).
|
|
- CI (`.gitea/workflows/check.yml`) is **eval-tier only**: the act_runner
|
|
is a docker container (no systemd, no /dev/kvm). Container gotchas are
|
|
documented in the workflow header (single-user Nix + nixbld users,
|
|
`sandbox=false` for Stylix IFD, Nix pinned 2.31.5 vs lazy-trees, no JS
|
|
actions past node20) — learned over the legacy repo's 57 runs; read
|
|
them before touching the workflow.
|
|
- The Gitea instance is **1.25.4** — `on: schedule` workflows are
|
|
supported; bump.yml assumes the Actions token can push to `main`
|
|
(standard Gitea behaviour, but unconfirmed until the first run lands).
|
|
- The git server is **Gitea** (gitea/act_runner via docker-compose), NOT
|
|
Forgejo — workflows are read from `.gitea/workflows/` (or `.github/`),
|
|
never `.forgejo/workflows/` (a whole push cycle was lost to that).
|
|
- Reusable headless VM harness: `checks.*` via runNixOSTest — existing
|
|
examples to crib from: `distro-id` (boots + `switch-to-configuration
|
|
dry-activate`), `hardware-toggles` (kernel cmdline/PAM assertions),
|
|
`battery-charge-limit` (fake Mains adapter via `test_power`, real udev
|
|
uevent, `InvocationID` change proves the restart).
|
|
- Themed-desktop screenshots work headlessly: software-GL Hyprland
|
|
(`LIBGL_ALWAYS_SOFTWARE` on virtio-gpu) + `machine.screenshot()` QMP
|
|
dump — prototyped 2026-06-19, kept as the fallback for theme previews
|
|
(§ Visual theme picker).
|
|
- Hyprland/Ghostty need guest GL (`virtio-vga-gl`, `gl=on`) in
|
|
interactive QEMU or the session won't start; black screen ≈ missing GL
|
|
(docs/TESTING.md § gotchas).
|
|
- No KVM = slow, not broken; don't read slowness as failure.
|
|
|
|
## Known-broken / watchlist
|
|
- **btrfs-assistant "segfault" was unprivileged-only** (re-diagnosed
|
|
2026-07-04): libbtrfsutil's unprivileged subvolume iteration crashes on
|
|
btrfs-progs 6.17.1 (upstream-fixed after); **as root it works**, and the
|
|
pkexec launcher runs it as root. The real distro bug was **no polkit
|
|
agent in the session** (every pkexec failed silently) — hyprpolkitagent
|
|
now ships (hyprland.nix exec-once). `checks.snapshot-gui` guards the
|
|
root path. Lesson: before "app X is broken", check WHO it runs as — and
|
|
whether polkit prompts can render at all (§ Snapshot browse/restore).
|
|
- **NixOS release bump is a trap:** the discarded attempt
|
|
(branch deleted 2026-06-22) hit a Hyprland OOM blocker; a redo is a
|
|
deliberate `v2`, never part of routine lock bumps.
|
|
- `theme-state.json` is git-tracked inside an 86 MB flake tree, so every
|
|
state write re-copies the source before eval — the wallpapers-artifact
|
|
split (BACKLOG LATER) is the decided fix (§ Faster switches).
|
|
|
|
## Design invariants
|
|
- **Waybar status is never color-only** (item 28 sweep, iteration #69):
|
|
every status module must distinguish its states by SHAPE (glyph) or
|
|
presence (self-hide), never color alone — good/warn/bad collapse under
|
|
color-blindness. When adding a state, give it a distinct glyph or gate
|
|
the module on it; a new `class` that only recolors an existing glyph is
|
|
a regression. Suppressed notification states (DND *and* app-inhibited)
|
|
all use the bell-off glyph + @muted.
|
|
|
|
## Gotchas (cost a debugging session once)
|
|
- Waybar `layer: top` renders above **even real-fullscreen windows** — the
|
|
bar draws over a fullscreen video. `layer: bottom` lets the fullscreen
|
|
surface cover it while the exclusive zone still reserves the bar's space
|
|
in normal tiling (trade-off: floating windows can now overlap the bar
|
|
strip). Set in both waybar.nix and every whole-swap jsonc (item 30).
|
|
- Hyprland binds match the exact modmask: a shifted keysym (`question`)
|
|
needs SHIFT in `mods` or the bind never fires — the keypress falls
|
|
through to the focused window (§ item 26; caught on hardware, invisible
|
|
to eval-tier tests).
|
|
- Never kill a Wayland session-lock client (hyprlock): its crash
|
|
failsafe drops to a tty instead of unlocking (§ Hibernate
|
|
double-unlock).
|
|
- rofi `element-icon size` is one value = a square cell; `WxH` silently
|
|
collapses and non-square icons letterbox — pre-crop images square at
|
|
build (§ Visual theme picker).
|
|
- WirePlumber 0.5 monitor rules can only early-match `device.api`;
|
|
`device.product.name` etc. bind *after* the rule runs — surgical
|
|
libcamera scoping is impossible (§ Webcam).
|
|
- `hyprctl switchxkblayout` is a *global* layout flip; per-device isolation
|
|
needs `device[<name>]:kb_layout` keywords (§ Keyboard layouts).
|
|
- Waybar's clock captures the timezone at construction — a zone change
|
|
needs SIGUSR2 (watcher in `timezone.nix`) (§ Automatic timezone).
|
|
- Waybar `persistent_workspaces` (underscore) is dead syntax silently
|
|
ignored; the hyphen form is honoured and renders phantom workspaces
|
|
(§ Waybar shows non-existent workspaces).
|
|
- GTK4/libadwaita/Qt6 read light/dark from the portal's
|
|
`org.freedesktop.appearance color-scheme` (dconf), not Stylix polarity
|
|
(§ GTK/Qt ignore the theme's mode).
|
|
- Update order matters downstream: `sys-update` (lock) before
|
|
`home-update`, or desktop changes are silently skipped against the old
|
|
lock (README § 3).
|
|
- Hyprland 0.53 rewrote window rules: `windowrulev2` is a hard error and
|
|
the old rule-first `float, class:^…$` no longer parses — both surface a
|
|
red config-error banner on the default desktop. Hyprlang legacy form is
|
|
now `<effect> <value>, match:<prop> ^…$` (e.g. `float 1, match:class ^…$`);
|
|
effects carry a value, matchers take `match:` (§ windowrule migration).
|
|
- grub `loadfont`s every `.pf2` in a theme dir — reuse a bundled DejaVu
|
|
rather than shipping fonts (§ Distro branding).
|
|
- `.claude/skills/*/SKILL.md` are now **tracked** (the `.gitignore`
|
|
`.claude/skills/` line was un-commented→removed, 7d52d4b) — commit skill
|
|
edits like any repo doc. Still never `git add -A` blindly: check
|
|
`git status --short` for genuine strangers first (`settings.local.json`,
|
|
harness-dropped files) and commit with explicit pathspecs (§ loop hygiene).
|