cdpearlman commited on
Commit
2f024ca
·
1 Parent(s): d075209

Improved rules and added claude.md

Browse files
.agents/rules/agent-workflow.md CHANGED
@@ -31,9 +31,9 @@ Interactive Dash app for exploring LLM internals through visualization and exper
31
  ## Data Files
32
  | File | Path | Purpose |
33
  |------|------|---------|
34
- | Sessions | `.context/data/sessions.md` | Running work log (append-only) |
35
- | Decisions | `.context/data/decisions.md` | Decision records with reasoning (append-only) |
36
- | Lessons | `.context/data/lessons.md` | Hard-won knowledge and past mistakes (append-only) |
37
 
38
  ## Memory Maintenance
39
 
@@ -49,13 +49,16 @@ Always look for opportunities to update the memory system:
49
  3. Never update memory mid-task without mentioning it
50
 
51
  **Rules**:
52
- - Data files are append-only — add entries, never remove or overwrite past entries
53
- - Modules can be edited but changes should be targeted, not full rewrites
54
- - After substantive work sessions, append a summary to `.context/data/sessions.md`
 
 
 
55
 
56
  ## Preferences
57
  - Don't ask permission for changes that fall within an approved plan — just execute
58
  - Commit normal changes to main; feature branches for major components/refactors. Never merge branches.
59
  - Keep `todo.md` and `plans.md` current before/after changes. Tasks should be atomic.
60
  - When in doubt, research options and make a minimal reasonable choice, noting it in `todo.md`
61
- - Explain manual tests clearly — what to look for, expected behavior, where to check
 
31
  ## Data Files
32
  | File | Path | Purpose |
33
  |------|------|---------|
34
+ | Sessions | `.context/data/sessions.md` | Running work log |
35
+ | Decisions | `.context/data/decisions.md` | Decision records with reasoning |
36
+ | Lessons | `.context/data/lessons.md` | Hard-won knowledge and past mistakes |
37
 
38
  ## Memory Maintenance
39
 
 
49
  3. Never update memory mid-task without mentioning it
50
 
51
  **Rules**:
52
+ - Data files are append-first with compression — new entries are appended, but older entries may be compressed when:
53
+ - **Conflicting information**: A newer entry supersedes an older one (e.g., a feature is replaced or deprecated). Compress the old entry into a brief note that preserves the history without full detail.
54
+ - **Excessive size**: When a file exceeds ~30 entries, summarize the oldest ~20 into a dense "Archive" block at the top (a few lines), retaining the most recent ~10 as full entries. This keeps long-term memory without bloating context.
55
+ - When compressing, never delete history entirely — always leave a condensed trace so the evolution of the project is visible.
56
+ - Modules can be edited but changes should be targeted, not full rewrites.
57
+ - After substantive work sessions, append a summary to `.context/data/sessions.md`.
58
 
59
  ## Preferences
60
  - Don't ask permission for changes that fall within an approved plan — just execute
61
  - Commit normal changes to main; feature branches for major components/refactors. Never merge branches.
62
  - Keep `todo.md` and `plans.md` current before/after changes. Tasks should be atomic.
63
  - When in doubt, research options and make a minimal reasonable choice, noting it in `todo.md`
64
+ - Explain manual tests clearly — what to look for, expected behavior, where to check
.claude/commands/update-memory.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ This session is wrapping up. Review what was accomplished and update the memory system per the CLAUDE.md instructions.
2
+
3
+ Steps:
4
+ 1. Run `git diff HEAD~3` and `git log --oneline -10` to see recent changes and commits from this session.
5
+ 2. Read the current state of the memory/data files:
6
+ - `.context/data/sessions.md` — append a session summary
7
+ - `.context/data/decisions.md` — append any decisions made with reasoning
8
+ - `.context/data/lessons.md` — append any hard-won knowledge or mistakes caught
9
+ 3. Check if any `.context/modules/` files need targeted updates based on what changed (new patterns, conventions, architecture shifts).
10
+ 4. For each proposed update: state which file changes and what the change is, then wait for approval before writing.
11
+ 5. Update `todo.md` and `plans.md` if tasks were completed or new ones emerged.
12
+
13
+ Additional context from the user (if any): $ARGUMENTS
.cursor/rules/AGENTS.md CHANGED
@@ -38,9 +38,9 @@ Interactive Dash app for exploring LLM internals through visualization and exper
38
  ## Data Files
39
  | File | Path | Purpose |
40
  |------|------|---------|
41
- | Sessions | `.context/data/sessions.md` | Running work log (append-only) |
42
- | Decisions | `.context/data/decisions.md` | Decision records with reasoning (append-only) |
43
- | Lessons | `.context/data/lessons.md` | Hard-won knowledge and past mistakes (append-only) |
44
 
45
  ## Memory Maintenance
46
 
@@ -56,9 +56,12 @@ Always look for opportunities to update the memory system:
56
  3. Never update memory mid-task without mentioning it
57
 
58
  **Rules**:
59
- - Data files are append-only — add entries, never remove or overwrite past entries
60
- - Modules can be edited but changes should be targeted, not full rewrites
61
- - After substantive work sessions, append a summary to `.context/data/sessions.md`
 
 
 
62
 
63
  ## Preferences
64
  - Don't ask permission for changes that fall within an approved plan — just execute
 
38
  ## Data Files
39
  | File | Path | Purpose |
40
  |------|------|---------|
41
+ | Sessions | `.context/data/sessions.md` | Running work log |
42
+ | Decisions | `.context/data/decisions.md` | Decision records with reasoning |
43
+ | Lessons | `.context/data/lessons.md` | Hard-won knowledge and past mistakes |
44
 
45
  ## Memory Maintenance
46
 
 
56
  3. Never update memory mid-task without mentioning it
57
 
58
  **Rules**:
59
+ - Data files are append-first with compression — new entries are appended, but older entries may be compressed when:
60
+ - **Conflicting information**: A newer entry supersedes an older one (e.g., a feature is replaced or deprecated). Compress the old entry into a brief note that preserves the history without full detail.
61
+ - **Excessive size**: When a file exceeds ~30 entries, summarize the oldest ~20 into a dense "Archive" block at the top (a few lines), retaining the most recent ~10 as full entries. This keeps long-term memory without bloating context.
62
+ - When compressing, never delete history entirely — always leave a condensed trace so the evolution of the project is visible.
63
+ - Modules can be edited but changes should be targeted, not full rewrites.
64
+ - After substantive work sessions, append a summary to `.context/data/sessions.md`.
65
 
66
  ## Preferences
67
  - Don't ask permission for changes that fall within an approved plan — just execute
CLAUDE.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Transformer Explanation Dashboard
2
+ Interactive Dash app for exploring LLM internals through visualization and experimentation. Built with Python, Dash, PyTorch, HF Transformers, Bertviz, pyvene.
3
+
4
+ ## Critical Rules
5
+ - **Dead code cleanup is mandatory during refactors.** Sweep for orphaned code from deprecated/deleted components every time.
6
+ - **Conceptual understanding over math rigor.** Skip complex derivations; focus on motivation and intuition that builds correct mental models.
7
+ - **Sanity check every change:** (1) Does this help someone learn about transformers? (2) Is the simplification accurate enough? (3) Am I in a rabbit hole?
8
+ - **TDD for backend logic.** Write failing tests first for anything in `utils/`. Skip tests for UI-only changes. Run `pytest` after every change; iterate until green.
9
+ - **Don't run the app.** Describe manual verification steps; the user will test themselves.
10
+ - **Surgical edits over rewrites.** Reuse existing files. Only create new modules when existing ones can't be extended.
11
+ - **No new dependencies** unless strictly necessary.
12
+ - **Push back on bad ideas.** Think through problems fully. Don't be a yes-man — challenge flawed approaches.
13
+ - **Components = layout only** (no ML logic). **Utils = computation only** (no Dash imports). **app.py = glue.**
14
+ - **Dash callbacks must stay responsive.** No heavy sync work in callbacks without feedback indicators.
15
+ - Don't reformat unrelated code or alter indentation styles.
16
+ - Check for zombie processes before debugging server errors.
17
+
18
+ ## Module Map
19
+ | Module | Path | Load when |
20
+ |--------|------|-----------|
21
+ | Product | `.context/modules/product.md` | Understanding vision, features, brand voice, visual identity, UX patterns |
22
+ | Architecture | `.context/modules/architecture.md` | Understanding system structure, data flow, or component boundaries |
23
+ | Conventions | `.context/modules/conventions.md` | Writing or reviewing code style, naming, commits, dead code cleanup |
24
+ | Education | `.context/modules/education.md` | Creating or editing educational content, visualizations, explanations |
25
+ | Testing | `.context/modules/testing.md` | Writing tests, running pytest, TDD workflow |
26
+
27
+ ## Data Files
28
+ | File | Path | Purpose |
29
+ |------|------|---------|
30
+ | Sessions | `.context/data/sessions.md` | Running work log |
31
+ | Decisions | `.context/data/decisions.md` | Decision records with reasoning |
32
+ | Lessons | `.context/data/lessons.md` | Hard-won knowledge and past mistakes |
33
+
34
+ ## Memory Maintenance
35
+
36
+ Always look for opportunities to update the memory system:
37
+ - **New patterns**: "We've been doing X consistently — should I add it to conventions?"
38
+ - **Decisions made**: "We decided Y — should I record this in decisions.md?"
39
+ - **Mistakes caught**: "This went wrong because Z — should I add it to lessons.md?"
40
+ - **Scope changes**: "The project now includes W — should I create a new module?"
41
+
42
+ **Before any memory update**:
43
+ 1. State which file(s) would change and what the change would be
44
+ 2. Wait for approval
45
+ 3. Never update memory mid-task without mentioning it
46
+
47
+ **Rules**:
48
+ - Data files are append-first with compression — new entries are appended, but older entries may be compressed when:
49
+ - **Conflicting information**: A newer entry supersedes an older one (e.g., a feature is replaced or deprecated). Compress the old entry into a brief note that preserves the history without full detail.
50
+ - **Excessive size**: When a file exceeds ~30 entries, summarize the oldest ~20 into a dense "Archive" block at the top (a few lines), retaining the most recent ~10 as full entries. This keeps long-term memory without bloating context.
51
+ - When compressing, never delete history entirely — always leave a condensed trace so the evolution of the project is visible.
52
+ - Modules can be edited but changes should be targeted, not full rewrites.
53
+ - After substantive work sessions, append a summary to `.context/data/sessions.md`.
54
+
55
+ ## Preferences
56
+ - Don't ask permission for changes that fall within an approved plan — just execute
57
+ - Commit normal changes to main; feature branches for major components/refactors. Never merge branches.
58
+ - Keep `todo.md` and `plans.md` current before/after changes. Tasks should be atomic.
59
+ - When in doubt, research options and make a minimal reasonable choice, noting it in `todo.md`
60
+ - Explain manual tests clearly — what to look for, expected behavior, where to check
RESEARCH-jargon-reduction.md ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # RESEARCH-jargon-reduction
2
+
3
+ ## Objective
4
+ Analyze the LLMVis project for technical jargon (e.g., "head", "ablation", "tokenizing") that may confuse younger or less technical audiences, and outline plain-English alternatives and explanations. The goal is to make the educational dashboard more accessible without completely losing technical accuracy.
5
+
6
+ ## Findings: Jargon in User-Facing Components
7
+
8
+ ### 1. "Ablation" / "Ablate"
9
+ **Locations found:**
10
+ - `app.py`: "Ablation" tab in the Investigation Panel
11
+ - `components/ablation_panel.py`: "What is Ablation?", "Add Head to Ablation List", "Run Ablation Experiment", "Ablated Output"
12
+
13
+ **Issue:** "Ablation" is a highly specialized term originally from neuroscience/medicine, adapted for machine learning to mean removing a component to observe its effect. It is completely opaque to a layperson.
14
+
15
+ **Proposed Replacements:**
16
+ - Replace primary "Ablation" headers with "Component Removal" or "Test by Removing".
17
+ - Replace "Run Ablation Experiment" with "Test What Happens When Removed".
18
+ - Keep "Ablation" only in an advanced glossary, a tooltip or as a secondary subtitle: "Test by Removing (Ablation)".
19
+
20
+ ### 2. "Token" / "Tokenization" / "Tokenizing"
21
+ **Locations found:**
22
+ - `app.py`: "Number of New Tokens"
23
+ - `components/pipeline.py`: "Tokenization" pipeline stage, "Your text is split into tokens"
24
+ - `components/investigation_panel.py`: "Token Attribution", "Target Token"
25
+
26
+ **Issue:** While "token" is explained somewhat in the app ("pieces that the model can understand"), phrases like "Token Attribution" or "Tokenization" sound overly academic as top-level headings.
27
+
28
+ **Proposed Replacements:**
29
+ - Use "Text Chunking" or "Word Pieces" as the primary heading, introducing "Tokens" as the technical equivalent inside the explanation.
30
+ - Change "Token Attribution" to "Which words influenced the answer?" or "Word Influence Score".
31
+
32
+ ### 3. "Attention Head" / "Head"
33
+ **Locations found:**
34
+ - `components/pipeline.py`: "Attention has multiple heads"
35
+ - `components/ablation_panel.py`: "Select heads to ablate", "Attention Head Roles"
36
+
37
+ **Issue:** "Head" in "Attention Head" is an architectural metaphor that doesn't organically mean anything to someone unfamiliar with the transformer architecture (multi-head attention).
38
+
39
+ **Proposed Replacements:**
40
+ - Reframe as "Attention Pattern", "Context Detector" or "Feature Spotter".
41
+ - Explain "Heads" as "Specialized Detectors" or "Information Filters" (e.g., "The model uses multiple 'Detectors' (called heads) to find relationships...").
42
+
43
+ ### 4. "Embedding" / "Vector"
44
+ **Locations found:**
45
+ - `components/pipeline.py`: "Embedding" stage, "high-dimensional vector", "lookup table"
46
+
47
+ **Issue:** "Vector" and "high-dimensional" sound like advanced mathematical phrases which may intimidate a younger user.
48
+
49
+ **Proposed Replacements:**
50
+ - Instead of "Embedding", use "Meaning Translation" or "Number Dictionary".
51
+ - Instead of "high-dimensional vector", use "list of numbers representing meaning".
52
+
53
+ ### 5. "MLP" / "Feed-Forward"
54
+ **Locations found:**
55
+ - `components/pipeline.py`: "MLP (Feed-Forward)", "MLP layers"
56
+
57
+ **Issue:** MLP (Multi-Layer Perceptron) is legacy neural network jargon that is not intuitive in the context of what it actually does (storing factual knowledge).
58
+
59
+ **Proposed Replacements:**
60
+ - Rename the pipeline stage to "Factual Knowledge" or "Memory Layers".
61
+ - Include "(MLP/Feed-Forward)" only as a small subtitle for those who want the exact technical term.
62
+
63
+ ### 6. "Logit" / "Probability" / "Activation Score"
64
+ **Locations found:**
65
+ - `components/ablation_panel.py`: "Average prob shift", "activation: 85%"
66
+
67
+ **Issue:** Jargon related to raw model outputs. "Activation score" sounds like a futuristic/sci-fi term.
68
+
69
+ **Proposed Replacements:**
70
+ - "Activation score" -> "Confidence level" or "Strength of focus".
71
+ - "Average prob shift" -> "Average change in confidence".
72
+
73
+ ## What Was Ruled Out
74
+ - **Completely eliminating all technical terms:** We ruled out removing words like "Token" or "Model" entirely because learning some valid terminology is part of the educational value of the tool. Instead, we will prioritize plain English for headings and actions, and introduce the technical terms in parentheses or explanatory sentences.
75
+ - **Rewriting the RAG Docs right now:** The `rag_docs/` folder contains extensive markdown documentation. For this primary pass, we ruled out modifying those long-form files, focusing entirely on the primary UI headers, buttons, and short stage descriptions in `app.py` and the `components/` directory to maximize immediate impact.
76
+
77
+ ## Next Steps
78
+ Review this document. If these jargon replacements aligned with the intended goal for younger audiences, we can draft `SPEC-jargon-reduction.md` with explicit strings to be updated across the application.
spec_attention_color_matching.md DELETED
@@ -1,199 +0,0 @@
1
- # SPEC: Head Color Swatches in LLMVis
2
- **Status:** Ready for implementation
3
- **Date:** 2026-03-05
4
-
5
- ---
6
-
7
- ## Goal
8
-
9
- Add colored square swatches next to attention head labels in:
10
- 1. The attention head category panels (pipeline.py)
11
- 2. The ablation panel's selected head chips (ablation_panel.py)
12
-
13
- The colors must match what BertViz's head_view renders for each head index, so students can visually correlate "L4-H11 [magenta square]" in the panel with the magenta checkbox in the BertViz visualization.
14
-
15
- ---
16
-
17
- ## Core Insight
18
-
19
- BertViz's `head_view(..., html_action='return')` returns the full JS inlined as a string. We can patch `d3.schemeCategory10` → a custom 24-color palette at generation time. The swatches in our UI then reference the same palette — perfect correlation, zero color collisions.
20
-
21
- **Why not schemeCategory10?** GPT-2 (default model) has 12 heads/layer. schemeCategory10 cycles every 10, so H10 = H0 (both blue) and H11 = H1 (both orange). That defeats the purpose.
22
-
23
- ---
24
-
25
- ## The Palette
26
-
27
- Dark24 (Plotly) with two near-invisible entries replaced:
28
-
29
- ```python
30
- BERTVIZ_HEAD_COLORS = [
31
- '#2E91E5', # H0 - blue
32
- '#E15F99', # H1 - pink-red
33
- '#1CA71C', # H2 - green
34
- '#FB0D0D', # H3 - red
35
- '#DA16FF', # H4 - purple
36
- '#00B4D8', # H5 - cyan (was #222A2A near-black → swapped)
37
- '#B68100', # H6 - gold
38
- '#06D6A0', # H7 - teal (was #750D86 very dark purple → swapped)
39
- '#EB663B', # H8 - orange
40
- '#511CFB', # H9 - indigo
41
- '#00A08B', # H10 - dark teal
42
- '#FB00D1', # H11 - magenta
43
- '#FC0080', # H12 - hot pink
44
- '#B2828D', # H13 - mauve
45
- '#6C7C32', # H14 - olive
46
- '#778AAE', # H15 - slate blue
47
- ]
48
- ```
49
-
50
- 16 colors covers all supported models (max 16 heads/layer: gpt2-medium, pythia-410m, Qwen2.5-0.5B).
51
-
52
- ---
53
-
54
- ## Files to Change
55
-
56
- ### 1. New file: `utils/colors.py`
57
- Define `BERTVIZ_HEAD_COLORS` here as the single source of truth. Import from here everywhere else.
58
-
59
- ```python
60
- """Shared color constants for LLMVis."""
61
-
62
- # 16-color palette for BertViz head_view.
63
- # Patched into BertViz at generation time (model_patterns.py) and mirrored
64
- # in UI swatches (pipeline.py, ablation_panel.py) for visual correlation.
65
- # Based on Plotly Dark24, with H5 and H7 replaced for legibility.
66
- BERTVIZ_HEAD_COLORS = [
67
- '#2E91E5', # H0 - blue
68
- '#E15F99', # H1 - pink-red
69
- '#1CA71C', # H2 - green
70
- '#FB0D0D', # H3 - red
71
- '#DA16FF', # H4 - purple
72
- '#00B4D8', # H5 - cyan
73
- '#B68100', # H6 - gold
74
- '#06D6A0', # H7 - teal
75
- '#EB663B', # H8 - orange
76
- '#511CFB', # H9 - indigo
77
- '#00A08B', # H10 - dark teal
78
- '#FB00D1', # H11 - magenta
79
- '#FC0080', # H12 - hot pink
80
- '#B2828D', # H13 - mauve
81
- '#6C7C32', # H14 - olive
82
- '#778AAE', # H15 - slate blue
83
- ]
84
-
85
- def head_color(head_index: int) -> str:
86
- """Return the swatch color for a given head index."""
87
- return BERTVIZ_HEAD_COLORS[head_index % len(BERTVIZ_HEAD_COLORS)]
88
- ```
89
-
90
- ---
91
-
92
- ### 2. `utils/model_patterns.py` — `generate_bertviz_html()`
93
-
94
- After the `head_view(...)` call, patch the returned HTML string to replace BertViz's default color scheme with ours. Both the primary and fallback d3 lines must be replaced.
95
-
96
- **Locate:** the `else:` block in `generate_bertviz_html()` (around line 1414):
97
- ```python
98
- html_result = head_view(attentions, tokens, html_action='return')
99
- return html_result.data if hasattr(html_result, 'data') else str(html_result)
100
- ```
101
-
102
- **Replace with:**
103
- ```python
104
- from utils.colors import BERTVIZ_HEAD_COLORS
105
- html_result = head_view(attentions, tokens, html_action='return')
106
- html_str = html_result.data if hasattr(html_result, 'data') else str(html_result)
107
-
108
- # Patch BertViz color scheme to match our swatch palette (no collisions for ≤16 heads)
109
- _colors_js = repr(BERTVIZ_HEAD_COLORS).replace("'", '"') # JSON-safe array literal
110
- _patch = f"headColors = d3.scaleOrdinal({_colors_js});"
111
- html_str = html_str.replace(
112
- 'headColors = d3.scaleOrdinal(d3.schemeCategory10);',
113
- _patch
114
- )
115
- html_str = html_str.replace(
116
- 'headColors = d3.scale.category10();',
117
- _patch
118
- )
119
- return html_str
120
- ```
121
-
122
- ---
123
-
124
- ### 3. `components/pipeline.py` — `create_attention_content()`
125
-
126
- Import `head_color` from `utils.colors` at the top of the file.
127
-
128
- In the `head_items` loop (around line 536), the head label is currently:
129
- ```python
130
- html.Span(label, style={
131
- 'fontFamily': 'monospace', 'fontSize': '12px', 'fontWeight': '500',
132
- 'minWidth': '60px', 'color': '#495057' if is_active else '#aaa',
133
- }, title=f"See Layer {head_info['layer']}, Head {head_info['head']} in the visualization below"),
134
- ```
135
-
136
- **Replace with:**
137
- ```python
138
- html.Span([
139
- html.Span("■ ", style={
140
- 'color': head_color(head_info['head']),
141
- 'fontSize': '14px',
142
- }),
143
- label
144
- ], style={
145
- 'fontFamily': 'monospace', 'fontSize': '12px', 'fontWeight': '500',
146
- 'minWidth': '60px', 'color': '#495057' if is_active else '#aaa',
147
- 'display': 'inline-flex', 'alignItems': 'center',
148
- }, title=f"See Layer {head_info['layer']}, Head {head_info['head']} in the visualization below"),
149
- ```
150
-
151
- Note: The swatch always renders at full color even for inactive heads — the parent `html.Div` already applies `opacity: 0.5` for inactive heads, which will naturally dim the swatch too. No special handling needed.
152
-
153
- ---
154
-
155
- ### 4. `components/ablation_panel.py` — `create_selected_heads_display()`
156
-
157
- Import `head_color` from `utils.colors` at the top of the file.
158
-
159
- In the chips loop, the label is currently:
160
- ```python
161
- label = f"L{layer}-H{head}"
162
-
163
- chips.append(
164
- html.Span([
165
- html.Span(label, style={'marginRight': '6px'}),
166
- ...
167
- ], ...)
168
- )
169
- ```
170
-
171
- **Replace** the `html.Span(label, ...)` with:
172
- ```python
173
- html.Span([
174
- html.Span("■ ", style={
175
- 'color': head_color(head),
176
- 'fontSize': '14px',
177
- 'marginRight': '2px',
178
- }),
179
- html.Span(label, style={'marginRight': '6px'}),
180
- ], style={'display': 'inline-flex', 'alignItems': 'center'}),
181
- ```
182
-
183
- ---
184
-
185
- ## Exit Criteria
186
-
187
- - [ ] BertViz head_view renders with the new palette — H0 is blue, H10 is dark teal, H11 is magenta (visually distinct from H1)
188
- - [ ] Every head label in the attention category panels shows a colored square matching BertViz
189
- - [ ] Every ablation chip shows a matching colored square
190
- - [ ] Spot checks: `L0-H0` = `#2E91E5`, `L4-H10` = `#00A08B`, `L4-H11` = `#FB00D1`
191
- - [ ] `BERTVIZ_HEAD_COLORS` / `head_color()` defined in exactly one place (`utils/colors.py`), imported everywhere else
192
- - [ ] No functional changes to callbacks, stores, or any other logic
193
- - [ ] Existing tests still pass
194
-
195
- ## Non-Goals
196
- - No changes to model_view (not used in this app)
197
- - No hover/interactive effects on swatches
198
- - No changes to per-category color scheme (the purple/blue/green category accent colors are separate)
199
- - No changes beyond the 4 files listed above