diff --git a/.gsd/milestones/M006/M006-ROADMAP.md b/.gsd/milestones/M006/M006-ROADMAP.md
index d989b6c..711eca0 100644
--- a/.gsd/milestones/M006/M006-ROADMAP.md
+++ b/.gsd/milestones/M006/M006-ROADMAP.md
@@ -8,7 +8,7 @@ Consolidate admin navigation into a dropdown, add head/tail log viewing and comm
|----|-------|------|---------|------|------------|
| S01 | Admin Navigation Dropdown + Header Cleanup | low | — | ✅ | Header shows Home, Topics, Creators, and an Admin dropdown. Clicking Admin reveals Review, Reports, Pipeline links. ModeToggle removed from header. |
| S02 | Pipeline Page: Head/Tail Log View + Token Count | low | — | ✅ | Pipeline event log shows Head/Tail toggle buttons. Head shows first N events, Tail shows last N events. Token counts visible per event and per video. |
-| S03 | Git Commit SHA in Pipeline Version Metadata | low | — | ⬜ | Running the pipeline captures the current git commit SHA. Viewing a technique page version shows the commit hash in the metadata panel. |
+| S03 | Git Commit SHA in Pipeline Version Metadata | low | — | ✅ | Running the pipeline captures the current git commit SHA. Viewing a technique page version shows the commit hash in the metadata panel. |
| S04 | Technique Page: Sidebar Reorder, Creator Emphasis, Tag Polish | medium | — | ⬜ | Technique page sidebar shows Plugins Referenced at top. Creator name is visually prominent. Tags use a coherent color system. |
| S05 | Topics Page Redesign + Music Theory Category | high | — | ⬜ | Topics page shows 7 categories (including Music Theory) with an improved visual layout — category cards with descriptions, sub-topic counts, better structure. |
| S06 | App Footer with Version Info | low | — | ⬜ | Every page shows a subtle footer with app version, build date, and optional repo link. |
diff --git a/.gsd/milestones/M006/slices/S03/S03-SUMMARY.md b/.gsd/milestones/M006/slices/S03/S03-SUMMARY.md
new file mode 100644
index 0000000..4db9d32
--- /dev/null
+++ b/.gsd/milestones/M006/slices/S03/S03-SUMMARY.md
@@ -0,0 +1,88 @@
+---
+id: S03
+parent: M006
+milestone: M006
+provides:
+ - git_commit_sha in pipeline_metadata dict
+ - Commit row in version metadata panel
+requires:
+ []
+affects:
+ - S06
+key_files:
+ - docker/Dockerfile.api
+ - docker-compose.yml
+ - backend/config.py
+ - backend/pipeline/stages.py
+ - frontend/src/pages/TechniquePage.tsx
+key_decisions:
+ - 4-tier SHA resolution: .git-commit file → git rev-parse → env/config → unknown
+ - Hide unknown SHA from UI — only render Commit row when a real hash was captured
+patterns_established:
+ - Docker build-arg → file → runtime reader pattern for baking build-time metadata into containers
+observability_surfaces:
+ - none
+drill_down_paths:
+ - .gsd/milestones/M006/slices/S03/tasks/T01-SUMMARY.md
+ - .gsd/milestones/M006/slices/S03/tasks/T02-SUMMARY.md
+duration: ""
+verification_result: passed
+completed_at: 2026-03-30T11:26:49.606Z
+blocker_discovered: false
+---
+
+# S03: Git Commit SHA in Pipeline Version Metadata
+
+**Pipeline now captures the git commit SHA at Docker build time and displays it in the technique page version metadata panel.**
+
+## What Happened
+
+Two tasks delivered the full vertical slice — backend SHA capture and frontend display.
+
+T01 added a `GIT_COMMIT_SHA` build arg to `Dockerfile.api` that writes the SHA to `/app/.git-commit` at build time. Both `chrysopedia-api` and `chrysopedia-worker` compose services pass this arg. A new `_get_git_commit_sha()` helper in `stages.py` resolves the SHA through a 4-tier fallback chain: (1) read `/app/.git-commit`, (2) run `git rev-parse --short HEAD`, (3) read `GIT_COMMIT_SHA` env var / config setting, (4) return `"unknown"`. The `_capture_pipeline_metadata()` function now includes `git_commit_sha` in its return dict.
+
+T02 added a conditional "Commit" row to the version metadata panel in `TechniquePage.tsx`. It reuses the existing `version-metadata__hash-value` monospace styling and displays only the first 7 characters. When the SHA is `"unknown"` (i.e., the image wasn't built with the arg), the row is hidden entirely.
+
+Verified: frontend builds with zero errors, `_capture_pipeline_metadata()` returns `git_commit_sha` key inside the running container. Currently returns `"unknown"` because the running containers pre-date the Dockerfile change — a `docker compose build` with `GIT_COMMIT_SHA=$(git rev-parse --short HEAD)` will bake in a real SHA.
+
+## Verification
+
+1. `ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia/frontend && npm run build 2>&1 | tail -5'` — exit 0, clean build in 696ms
+2. `docker exec chrysopedia-api python -c "from pipeline.stages import _capture_pipeline_metadata; ..."` — exit 0, git_commit_sha key present with "unknown" fallback
+3. Grep confirmed all 5 files contain the expected code changes on ub01
+
+## Requirements Advanced
+
+None.
+
+## Requirements Validated
+
+None.
+
+## New Requirements Surfaced
+
+None.
+
+## Requirements Invalidated or Re-scoped
+
+None.
+
+## Deviations
+
+T02 added a filter to hide "unknown" SHA from the UI — not in the original plan but a sensible UX decision (showing literal "unknown" is meaningless to users).
+
+## Known Limitations
+
+Running containers still use the old image without .git-commit baked in. A `docker compose build --build-arg GIT_COMMIT_SHA=$(git rev-parse --short HEAD)` is needed to see real SHAs. This is expected — the build/deploy step is outside slice scope.
+
+## Follow-ups
+
+Consider adding GIT_COMMIT_SHA to the CI/CD build command or a Makefile target so rebuilds automatically capture the SHA.
+
+## Files Created/Modified
+
+- `docker/Dockerfile.api` — Added GIT_COMMIT_SHA build arg and RUN echo to write SHA to /app/.git-commit
+- `docker-compose.yml` — Added GIT_COMMIT_SHA build arg to both chrysopedia-api and chrysopedia-worker services
+- `backend/config.py` — Added git_commit_sha field to Settings class with 'unknown' default
+- `backend/pipeline/stages.py` — Added _get_git_commit_sha() helper with 4-tier fallback; added git_commit_sha to _capture_pipeline_metadata()
+- `frontend/src/pages/TechniquePage.tsx` — Added conditional Commit row to version metadata panel with 7-char abbreviated SHA
diff --git a/.gsd/milestones/M006/slices/S03/S03-UAT.md b/.gsd/milestones/M006/slices/S03/S03-UAT.md
new file mode 100644
index 0000000..34bafce
--- /dev/null
+++ b/.gsd/milestones/M006/slices/S03/S03-UAT.md
@@ -0,0 +1,57 @@
+# S03: Git Commit SHA in Pipeline Version Metadata — UAT
+
+**Milestone:** M006
+**Written:** 2026-03-30T11:26:49.606Z
+
+## UAT: Git Commit SHA in Pipeline Version Metadata
+
+### Preconditions
+- Chrysopedia stack running on ub01 (`docker ps --filter name=chrysopedia` shows all services)
+- At least one technique page exists with version data (from a prior pipeline run)
+- Access to ub01 via SSH
+
+### Test 1: Backend — SHA present in pipeline metadata
+**Steps:**
+1. SSH to ub01
+2. Run: `docker exec chrysopedia-api python -c "from pipeline.stages import _capture_pipeline_metadata; import json; m = _capture_pipeline_metadata(); print(json.dumps(m, indent=2))"`
+3. Verify output contains `"git_commit_sha"` key
+
+**Expected:** Key is present. Value is `"unknown"` on current containers (pre-rebuild) or a 7+ char hex string after rebuild.
+
+### Test 2: Backend — SHA resolution fallback chain
+**Steps:**
+1. Run: `docker exec chrysopedia-api python -c "from pipeline.stages import _get_git_commit_sha; print(repr(_get_git_commit_sha()))"`
+2. Verify returns a string (not None, not an exception)
+
+**Expected:** Returns `'unknown'` in current container (no .git-commit file, no git binary). After `docker compose build --build-arg GIT_COMMIT_SHA=$(git rev-parse --short HEAD)`, returns the actual short SHA.
+
+### Test 3: Frontend — Build succeeds with commit SHA rendering code
+**Steps:**
+1. SSH to ub01
+2. Run: `cd /vmPool/r/repos/xpltdco/chrysopedia/frontend && npm run build`
+3. Verify exit code 0, no TypeScript errors
+
+**Expected:** Clean build, zero errors.
+
+### Test 4: Frontend — Commit row hidden when SHA is "unknown"
+**Steps:**
+1. Open http://ub01:8096 in browser
+2. Navigate to any technique page with version history
+3. Expand a version's metadata panel
+4. Look for a "Commit" row
+
+**Expected:** No "Commit" row visible (current containers have "unknown" SHA, which is filtered out).
+
+### Test 5: Frontend — Commit row visible after rebuild with real SHA
+**Precondition:** Rebuild images with SHA: `cd /vmPool/r/repos/xpltdco/chrysopedia && GIT_COMMIT_SHA=$(git rev-parse --short HEAD) docker compose build chrysopedia-api && docker compose up -d`
+**Steps:**
+1. Re-run the pipeline on any video (or wait for next scheduled run)
+2. Navigate to the resulting technique page's version metadata panel
+3. Look for a "Commit" row
+
+**Expected:** "Commit" row shows a 7-character hex string (e.g., `a1b2c3d`), rendered in monospace font matching the prompt hash styling.
+
+### Edge Cases
+- **No version data:** Technique pages without version history don't show the metadata panel at all — no crash expected.
+- **SHA longer than 7 chars:** Display truncates to first 7 characters regardless of full SHA length.
+- **Empty string SHA:** Treated same as any non-"unknown" value — would show empty code tag. Low risk since the fallback chain always produces either a real SHA or "unknown".
diff --git a/.gsd/milestones/M006/slices/S03/tasks/T02-VERIFY.json b/.gsd/milestones/M006/slices/S03/tasks/T02-VERIFY.json
new file mode 100644
index 0000000..b1af370
--- /dev/null
+++ b/.gsd/milestones/M006/slices/S03/tasks/T02-VERIFY.json
@@ -0,0 +1,18 @@
+{
+ "schemaVersion": 1,
+ "taskId": "T02",
+ "unitId": "M006/S03/T02",
+ "timestamp": 1774869947205,
+ "passed": false,
+ "discoverySource": "task-plan",
+ "checks": [
+ {
+ "command": "ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia/frontend",
+ "exitCode": 2,
+ "durationMs": 7,
+ "verdict": "fail"
+ }
+ ],
+ "retryAttempt": 1,
+ "maxRetries": 2
+}
diff --git a/.gsd/milestones/M006/slices/S04/S04-PLAN.md b/.gsd/milestones/M006/slices/S04/S04-PLAN.md
index e2b74bd..b64c138 100644
--- a/.gsd/milestones/M006/slices/S04/S04-PLAN.md
+++ b/.gsd/milestones/M006/slices/S04/S04-PLAN.md
@@ -1,6 +1,95 @@
# S04: Technique Page: Sidebar Reorder, Creator Emphasis, Tag Polish
-**Goal:** Improve technique page visual hierarchy: plugins first in sidebar, creator stands out, tags make sense
+**Goal:** Technique page sidebar shows Plugins Referenced at top. Creator name is visually prominent in a dedicated row. Category badges use per-category colors.
**Demo:** After this: Technique page sidebar shows Plugins Referenced at top. Creator name is visually prominent. Tags use a coherent color system.
## Tasks
+- [x] **T01: Reordered technique page sidebar (plugins first), added prominent creator block with genre pills, and implemented per-category badge color system with 6 category-specific color pairs** — Single task covering all three S04 concerns in TechniquePage.tsx and App.css.
+
+## Steps
+
+1. **Sidebar reorder in TechniquePage.tsx** (~line 408–510 in the sidebar column):
+ - Move the `{displayPlugins && displayPlugins.length > 0 && ( ... )}` JSX block so it appears FIRST inside `
`, before the key moments section.
+ - Final sidebar order: Plugins Referenced → Key Moments → Signal Chains → Related Techniques.
+
+2. **Creator emphasis in TechniquePage.tsx** (~line 232–248, the `technique-header__meta` div):
+ - Remove the `` from inside `technique-header__meta`.
+ - Add a new `
` between the `
` title and the `technique-header__meta` div.
+ - Inside the creator block, render:
+ ```tsx
+ {technique.creator_info && (
+
+ )}
+ ```
+
+3. **Creator emphasis CSS in App.css** (after the existing `.technique-header__title` styles, ~line 1296):
+ - Add `.technique-header__creator-block` — `display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.5rem;`
+ - Add `.technique-header__creator-link` — `font-size: 1.125rem; font-weight: 600; color: var(--color-link-accent); text-decoration: none;`
+ - Add `.technique-header__creator-link:hover` — `text-decoration: underline; color: var(--color-accent-hover);`
+ - Add `.pill--genre-small` — `font-size: 0.625rem; padding: 0.0625rem 0.375rem; background: var(--color-pill-bg); color: var(--color-text-secondary);`
+ - Remove the old `.technique-header__creator` and `.technique-header__creator:hover` rules.
+
+4. **Category color variables in App.css** (add to the `:root` block, after the existing `--color-badge-category-*` variables):
+ ```css
+ /* Per-category badge colors */
+ --color-badge-cat-sound-design-bg: #0d3b3b;
+ --color-badge-cat-sound-design-text: #5eead4;
+ --color-badge-cat-mixing-bg: #2e1065;
+ --color-badge-cat-mixing-text: #c4b5fd;
+ --color-badge-cat-synthesis-bg: #0c2461;
+ --color-badge-cat-synthesis-text: #93c5fd;
+ --color-badge-cat-arrangement-bg: #422006;
+ --color-badge-cat-arrangement-text: #fcd34d;
+ --color-badge-cat-workflow-bg: #052e16;
+ --color-badge-cat-workflow-text: #6ee7b7;
+ --color-badge-cat-mastering-bg: #4a1035;
+ --color-badge-cat-mastering-text: #f9a8d4;
+ ```
+
+5. **Category badge CSS classes in App.css** (after the existing `.badge--category` rule):
+ ```css
+ .badge--cat-sound-design { background: var(--color-badge-cat-sound-design-bg); color: var(--color-badge-cat-sound-design-text); }
+ .badge--cat-mixing { background: var(--color-badge-cat-mixing-bg); color: var(--color-badge-cat-mixing-text); }
+ .badge--cat-synthesis { background: var(--color-badge-cat-synthesis-bg); color: var(--color-badge-cat-synthesis-text); }
+ .badge--cat-arrangement { background: var(--color-badge-cat-arrangement-bg); color: var(--color-badge-cat-arrangement-text); }
+ .badge--cat-workflow { background: var(--color-badge-cat-workflow-bg); color: var(--color-badge-cat-workflow-text); }
+ .badge--cat-mastering { background: var(--color-badge-cat-mastering-bg); color: var(--color-badge-cat-mastering-text); }
+ ```
+
+6. **Dynamic category class in TechniquePage.tsx** — in the header where the category badge is rendered (~line 234):
+ - Change `{displayCategory}` to:
+ ```tsx
+
+ {displayCategory}
+
+ ```
+ - The `.badge--category` base style (indigo) remains as fallback for any unrecognized category.
+
+7. **Verify:** Run `cd frontend && npx tsc --noEmit && npx vite build` — both must pass with zero errors.
+
+## Must-Haves
+
+- [ ] Sidebar Plugins Referenced section appears first in the sidebar column
+- [ ] Creator block sits between the title h1 and the meta row, not inline with badges
+- [ ] Creator link uses font-size >= 1rem and font-weight 600
+- [ ] Creator genres render as small pills when present
+- [ ] 12 new CSS custom properties for 6 category color pairs
+- [ ] 6 `.badge--cat-*` CSS classes using the custom properties
+- [ ] Category badge JSX derives class from topic_category with slug conversion
+- [ ] Base `.badge--category` (indigo) remains as fallback for unknown categories
+- [ ] TypeScript compilation passes
+- [ ] Vite production build succeeds
+ - Estimate: 45m
+ - Files: frontend/src/pages/TechniquePage.tsx, frontend/src/App.css
+ - Verify: cd frontend && npx tsc --noEmit && npx vite build
diff --git a/.gsd/milestones/M006/slices/S04/S04-RESEARCH.md b/.gsd/milestones/M006/slices/S04/S04-RESEARCH.md
new file mode 100644
index 0000000..5dbe497
--- /dev/null
+++ b/.gsd/milestones/M006/slices/S04/S04-RESEARCH.md
@@ -0,0 +1,111 @@
+# S04 Research — Technique Page: Sidebar Reorder, Creator Emphasis, Tag Polish
+
+## Summary
+
+This is a **light research** slice — purely frontend CSS + JSX changes to one page (`TechniquePage.tsx`) and the shared stylesheet (`App.css`). No backend changes, no new APIs, no new dependencies. All work follows established patterns already in the codebase.
+
+Three independent concerns, all in the same two files:
+1. **Sidebar reorder:** Move "Plugins Referenced" section to the top of the sidebar
+2. **Creator emphasis:** Make the creator name visually prominent (currently a small 0.875rem cyan link inline with other meta)
+3. **Tag polish:** Implement a coherent color system for the 6 `topic_category` badges and the `topic_tags` pills
+
+## Recommendation
+
+Execute as a single task. All three changes are in `TechniquePage.tsx` (JSX order + minor markup) and `App.css` (new category color variables + creator styling + possible tag pill variants). The changes are small enough that splitting into multiple tasks would add more overhead than value.
+
+## Implementation Landscape
+
+### Files to Modify
+
+| File | What changes |
+|------|-------------|
+| `frontend/src/pages/TechniquePage.tsx` | Reorder sidebar sections (move Plugins above Key Moments); restructure creator display from inline link to a more prominent block |
+| `frontend/src/App.css` | Add per-category color variables; add creator emphasis styles; optionally refine pill styles for tag coherence |
+
+### 1. Sidebar Reorder
+
+Current sidebar order in `TechniquePage.tsx` (lines ~400–510):
+1. Key Moments (`technique-moments`)
+2. Signal Chains (`technique-chains`)
+3. Plugins Referenced (`technique-plugins`)
+4. Related Techniques (`technique-related`)
+
+Target order:
+1. **Plugins Referenced** (moved to top)
+2. Key Moments
+3. Signal Chains
+4. Related Techniques
+
+This is a pure JSX block reorder — move the `{displayPlugins && ...}` block before the `{technique.key_moments.length > 0 && ...}` block. No logic changes.
+
+### 2. Creator Emphasis
+
+Current state: Creator is a small `` with class `technique-header__creator` rendered inline inside the `technique-header__meta` flex row alongside the category badge and topic tags. Styled as `font-size: 0.875rem; color: var(--color-link-accent)`.
+
+The creator link text is `by {technique.creator_info.name}`.
+
+Options for emphasis:
+- **A) Larger text + dedicated row:** Pull the creator out of the `technique-header__meta` flex row and render it as its own line below the title, e.g., `
`. Larger font (1rem–1.125rem), bolder weight. Still a link. Can optionally show genre pills from `creator_info.genres`.
+- **B) Keep inline but increase visual weight:** Bump font-size to 1rem, add font-weight 600, drop the "by" prefix, make the name the primary visual anchor.
+
+**Recommendation: Option A.** A dedicated row between the title and the meta row gives the creator name room to breathe. The `CreatorInfo` type already includes `genres: string[] | null` which can be shown as small pills next to the name.
+
+### 3. Tag Color System
+
+Current state: All `topic_tags` pills use the same generic `--color-pill-bg` (#22222e) / `--color-pill-text` (#e2e2ea). The `topic_category` badge uses `--color-badge-category-bg` (#1e1b4b indigo) / `--color-badge-category-text` (#93c5fd blue).
+
+There are 6 canonical categories from `config/canonical_tags.yaml`:
+1. **Sound design** — creating/shaping sounds
+2. **Mixing** — balancing/processing
+3. **Synthesis** — generating sound
+4. **Arrangement** — song structure
+5. **Workflow** — creative process/productivity
+6. **Mastering** — final processing
+
+A "coherent color system" means the category badge gets a distinct color per category, and the topic_tags pills under that category should feel visually related.
+
+**Approach:** Add 6 pairs of CSS variables for category badges:
+```
+--color-badge-cat-{slug}-bg / --color-badge-cat-{slug}-text
+```
+
+In the JSX, derive a CSS class from the `topic_category` string:
+```tsx
+const catSlug = displayCategory?.toLowerCase().replace(/\s+/g, '-');
+className={`badge badge--category badge--cat-${catSlug}`}
+```
+
+The 6 category colors (dark-mode appropriate, low-saturation backgrounds with readable text):
+
+| Category | BG | Text | Vibe |
+|----------|-----|------|------|
+| Sound design | deep teal | bright teal | creation/sound |
+| Mixing | deep purple | light purple | processing |
+| Synthesis | deep blue | light blue | waveforms |
+| Arrangement | deep amber | light amber | structure |
+| Workflow | deep green | light green | productivity |
+| Mastering | deep rose | light rose | polish/finish |
+
+For `topic_tags` pills: keep the current neutral style. The category badge provides the color identity; making every tag colorful would be visually noisy. The pills can get a subtle left-border or slight tint matching their category if desired, but the default neutral pill is fine.
+
+### Existing CSS Variable Pattern
+
+All colors are defined as CSS custom properties in `:root` (lines 3–118 of App.css). The project uses a dark theme with `#0f0f14` page background, cyan (`#22d3ee`) accent, and semantic variable names. Per D017, there are 77 variables. Adding 12 more (6 categories × bg+text) is consistent with the pattern.
+
+### Verification
+
+- `cd frontend && npx tsc --noEmit` — zero TypeScript errors
+- `cd frontend && npx vite build` — production build succeeds
+- Visual verification via browser at the running app (http://ub01:8096) after `docker compose build && docker compose up -d` on ub01
+
+### Risk: Category String Matching
+
+The `topic_category` values come from the database. They are stored as user-facing strings like "Sound design", not slugs. The CSS class derivation (`toLowerCase().replace(/\s+/g, '-')`) must match the CSS selectors exactly. Fallback: the base `.badge--category` style applies when no category-specific class matches, so unknown categories get the current indigo styling.
+
+### No Backend Changes Needed
+
+The API already returns `creator_info` (with name, slug, genres), `topic_category`, `topic_tags`, and `plugins`. All data needed for these UI changes is already available in the frontend.
+
+### No New Dependencies
+
+Pure CSS + JSX changes within the existing React/Vite/TypeScript stack.
diff --git a/.gsd/milestones/M006/slices/S04/tasks/T01-PLAN.md b/.gsd/milestones/M006/slices/S04/tasks/T01-PLAN.md
new file mode 100644
index 0000000..2b53420
--- /dev/null
+++ b/.gsd/milestones/M006/slices/S04/tasks/T01-PLAN.md
@@ -0,0 +1,108 @@
+---
+estimated_steps: 76
+estimated_files: 2
+skills_used: []
+---
+
+# T01: Reorder sidebar, add creator emphasis block, implement per-category badge colors
+
+Single task covering all three S04 concerns in TechniquePage.tsx and App.css.
+
+## Steps
+
+1. **Sidebar reorder in TechniquePage.tsx** (~line 408–510 in the sidebar column):
+ - Move the `{displayPlugins && displayPlugins.length > 0 && ( ... )}` JSX block so it appears FIRST inside `
`, before the key moments section.
+ - Final sidebar order: Plugins Referenced → Key Moments → Signal Chains → Related Techniques.
+
+2. **Creator emphasis in TechniquePage.tsx** (~line 232–248, the `technique-header__meta` div):
+ - Remove the `` from inside `technique-header__meta`.
+ - Add a new `
` between the `
` title and the `technique-header__meta` div.
+ - Inside the creator block, render:
+ ```tsx
+ {technique.creator_info && (
+