Lesson #1462
← Back to Knowledge Board
Structural fixes vs band-aid (Pflasterarbeit) β find root rules first
- ID
- 1462
- Author
- Agent
- agent-claude
- Reviewed
- ✓ Yes
- Source authority
- 75 / 100
- Source
- User explicit: "alles nachhaltig beheben, keine pflasterarbeite" β patch base rules, not symptom-only
- Source issue
- β
- Created at
- 2026-05-12T10:00:23.509695+00:00
- Valid until
- β
- Deprecated at
- β
- Supersedes
- β
- Obsidian path
- /root/.claude/projects/-nvmetank1-projects/memory/feedback_structural_vs_bandaid.md
- Obsidian hash
- 428a9240a6058b43284780ea6ba1bb1e
- Tags
- claude-memory,feedback
Content
**Rule:** When fixing CSS/JS/architectural bugs, locate the **base/root definition** of the buggy class/rule, not just the responsive variant or specific instance. User said 2026-05-05: "genau, alles nachhaltig beheben, keine pflasterarbeite. baue handler, baue css fixes usw."
**Why:** Cost in churn. yoga#92 (dropdown clipping) had THREE PRs before the actual fix:
- PR #93 (or-loop drifted off-target β unrelated href bugs)
- PR #94 (only fixed `@media` mobile variant of `.card-box{overflow:hidden}`)
- PR #96 (FINALLY fixed the BASE rule at line 414 of `_ui_css.py` that applied at all screen sizes)
Same with the calendar popup (yoga#90 β PR #90 superficial; PR #96 added bulletproof handlers in capture phase + global window exposure).
**How to apply:**
1. **CSS bug** β `grep -n "\.classname\s*{" file.css`. Find ALL definitions, not just the first match. Check base + every `@media` variant.
2. **JS handler bug** β verify the function is actually IN SCOPE at click-time. Add `window.X = X` for globally-bound `onclick=` attrs that may run in different scope. Use **delegated handler in capture phase** at document level for bulletproof binding.
3. **Race conditions** β if a 3rd-party lib (FullCalendar, Bootstrap modal) intercepts events, your `addEventListener('click', β¦, true)` (capture=true) runs FIRST.
4. **Belt-and-suspenders** β apply both class-toggle AND inline-style for show/hide, in case CSS selector specificity loses to !important elsewhere.
5. **Test the deployed code** β after each fix, `docker exec <container> grep -c "<expected-marker>" /app/<file>` to confirm the change is live.
**Anti-patterns to recognize:**
- Patching only the `@media` variant when base rule has same bug
- Adding type="button" without verifying that's actually the click-failure cause
- Trusting `onclick="closeX()"` when X may not be in scope
- Spawning agents on already-failing tasks instead of orchestrator-direct edit when the bug-location is clear
**Heuristic when to go orchestrator-direct (vs delegating to agents):**
- Bug location is precisely known (file:line from user-report or grep)
- Fix is < 30 LOC
- Agent has failed 2+ times on same prompt (or-loop drift signal)
- User says "still not fixed" β second-iteration on same bug
**Reference PRs that demonstrate sustainable fixes:**
- yoga#66 (buttons F26+F31+F36 root cause: 110-line cascade-war β 8-line canonical)
- yoga#94β#96 (.card-box overflow root rule, not @media variant)
- yoga#96 (delegated capture-phase click handler bypassing FullCalendar event-grab)
- glug#841 (port of yoga#96 β same root cause both repos)
- yoga#97 (belt-and-suspenders inline-style needs symmetric clear β open() must `style.display=''` before classList.add since inline > class specificity)
**Anti-pattern: asymmetric open/close**
If close() sets inline `style.display='none'` as fallback, open() MUST clear inline first. Otherwise inline-style wins forever after first close. Pattern:
```js
function open(){ el.style.display=''; el.classList.add('open'); }
function close(){ el.classList.remove('open'); el.style.display='none'; }
```