chore: Added GIT_COMMIT_SHA build arg to Dockerfile.api, compose build…
- "docker/Dockerfile.api" - "docker-compose.yml" - "backend/config.py" - "backend/pipeline/stages.py" GSD-Task: S03/T01
This commit is contained in:
parent
ee24731e59
commit
12f9fb7334
10 changed files with 450 additions and 2 deletions
|
|
@ -35,3 +35,4 @@ Five milestones complete. The system is deployed and running on ub01 at `http://
|
||||||
| M003 | Domain + DNS + Per-Stage LLM Model Routing | ✅ Complete |
|
| M003 | Domain + DNS + Per-Stage LLM Model Routing | ✅ Complete |
|
||||||
| M004 | UI Polish, Bug Fixes, Technique Page Redesign, and Article Versioning | ✅ Complete |
|
| M004 | UI Polish, Bug Fixes, Technique Page Redesign, and Article Versioning | ✅ Complete |
|
||||||
| M005 | Pipeline Dashboard, Technique Page Redesign, Key Moment Cards | ✅ Complete |
|
| M005 | Pipeline Dashboard, Technique Page Redesign, Key Moment Cards | ✅ Complete |
|
||||||
|
| M006 | Admin Nav, Pipeline Log Views, Commit SHA, Tag Polish, Topics Redesign, Footer | 🔄 Active |
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ Consolidate admin navigation into a dropdown, add head/tail log viewing and comm
|
||||||
| ID | Slice | Risk | Depends | Done | After this |
|
| ID | Slice | Risk | Depends | Done | After this |
|
||||||
|----|-------|------|---------|------|------------|
|
|----|-------|------|---------|------|------------|
|
||||||
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
||||||
|
|
|
||||||
91
.gsd/milestones/M006/slices/S02/S02-SUMMARY.md
Normal file
91
.gsd/milestones/M006/slices/S02/S02-SUMMARY.md
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
---
|
||||||
|
id: S02
|
||||||
|
parent: M006
|
||||||
|
milestone: M006
|
||||||
|
provides:
|
||||||
|
- Pipeline events endpoint supports order=asc|desc query parameter
|
||||||
|
- EventLog component has Head/Tail view mode toggle
|
||||||
|
requires:
|
||||||
|
[]
|
||||||
|
affects:
|
||||||
|
[]
|
||||||
|
key_files:
|
||||||
|
- backend/routers/pipeline.py
|
||||||
|
- frontend/src/api/public-client.ts
|
||||||
|
- frontend/src/pages/AdminPipeline.tsx
|
||||||
|
- frontend/src/App.css
|
||||||
|
key_decisions:
|
||||||
|
- Used explicit string validation with 400 response for order param rather than FastAPI Literal/Enum, consistent with existing endpoint param style
|
||||||
|
- Placed segmented toggle between event count and refresh button in the header row for natural scan order
|
||||||
|
patterns_established:
|
||||||
|
- (none)
|
||||||
|
observability_surfaces:
|
||||||
|
- none
|
||||||
|
drill_down_paths:
|
||||||
|
- .gsd/milestones/M006/slices/S02/tasks/T01-SUMMARY.md
|
||||||
|
- .gsd/milestones/M006/slices/S02/tasks/T02-SUMMARY.md
|
||||||
|
duration: ""
|
||||||
|
verification_result: passed
|
||||||
|
completed_at: 2026-03-30T11:16:39.374Z
|
||||||
|
blocker_discovered: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# S02: Pipeline Page: Head/Tail Log View + Token Count
|
||||||
|
|
||||||
|
**Added Head/Tail toggle to pipeline event log — Head shows oldest events first (asc), Tail shows newest (desc) — with backend `order` query parameter, segmented toggle UI, and preserved token count display.**
|
||||||
|
|
||||||
|
## What Happened
|
||||||
|
|
||||||
|
Two-task slice adding chronological viewing to the pipeline event log.
|
||||||
|
|
||||||
|
**T01 (Backend):** Added `order` query parameter (asc/desc, default desc) to `GET /admin/pipeline/events/{video_id}`. Explicit string validation returns 400 for invalid values. Default remains desc for backward compatibility. Deployed and verified against live API on ub01.
|
||||||
|
|
||||||
|
**T02 (Frontend):** Added `viewMode` state (head/tail) to the EventLog component with a segmented toggle button UI. Head passes `order=asc`, Tail passes `order=desc`. Switching mode resets pagination offset to 0. API client updated to pass the `order` param. Segmented button CSS uses existing CSS custom properties. Token counts per-event and per-video remain visible and unchanged.
|
||||||
|
|
||||||
|
The slice is intentionally minimal — two files touched on the backend, three on the frontend. No schema changes, no new models, no new dependencies.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
All slice-level verification checks passed:
|
||||||
|
|
||||||
|
1. **order=asc** — `curl 'http://ub01:8096/api/v1/admin/pipeline/events/{vid}?order=asc&limit=3'` returns events with ascending timestamps (earliest: 2026-03-30T09:39:36, stage2_segmentation start)
|
||||||
|
2. **order=desc** — Same endpoint with `order=desc` returns most recent events first (latest: 2026-03-30T10:34:31, stage5_synthesis complete)
|
||||||
|
3. **order=invalid** — Returns HTTP 400
|
||||||
|
4. **No order param** — Defaults to desc (backward compatible)
|
||||||
|
5. **Frontend build** — `npm run build` exits 0, zero TypeScript errors, 786ms build time
|
||||||
|
6. **Token counts** — API response includes prompt_tokens, completion_tokens, total_tokens on llm_call events (confirmed in asc/desc responses)
|
||||||
|
|
||||||
|
## Requirements Advanced
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Requirements Validated
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## New Requirements Surfaced
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Requirements Invalidated or Re-scoped
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Deviations
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Known Limitations
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Follow-ups
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `backend/routers/pipeline.py` — Added order query parameter (asc/desc, default desc) to list_pipeline_events with validation and dynamic ordering
|
||||||
|
- `frontend/src/api/public-client.ts` — Added order param to fetchPipelineEvents params type and URL builder
|
||||||
|
- `frontend/src/pages/AdminPipeline.tsx` — Added viewMode state, Head/Tail segmented toggle, order param wiring, and pagination reset on mode switch
|
||||||
|
- `frontend/src/App.css` — Added segmented toggle button CSS (.pipeline-events__view-toggle, .pipeline-events__view-btn)
|
||||||
55
.gsd/milestones/M006/slices/S02/S02-UAT.md
Normal file
55
.gsd/milestones/M006/slices/S02/S02-UAT.md
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
# S02: Pipeline Page: Head/Tail Log View + Token Count — UAT
|
||||||
|
|
||||||
|
**Milestone:** M006
|
||||||
|
**Written:** 2026-03-30T11:16:39.374Z
|
||||||
|
|
||||||
|
## UAT: Pipeline Page Head/Tail Log View + Token Count
|
||||||
|
|
||||||
|
### Preconditions
|
||||||
|
- Chrysopedia stack running on ub01 (`docker ps --filter name=chrysopedia` shows all services healthy)
|
||||||
|
- At least one video has been processed through the pipeline (has pipeline events)
|
||||||
|
- Browser can reach http://ub01:8096
|
||||||
|
|
||||||
|
### Test 1: Head/Tail Toggle Visibility
|
||||||
|
1. Navigate to http://ub01:8096
|
||||||
|
2. Open Admin dropdown → click Pipeline
|
||||||
|
3. Expand any video with pipeline events
|
||||||
|
4. **Expected:** Event log header shows "Head" and "Tail" buttons between the event count and the refresh button
|
||||||
|
5. **Expected:** "Tail" button is active by default (highlighted/selected state)
|
||||||
|
|
||||||
|
### Test 2: Tail Mode (Default) Shows Newest First
|
||||||
|
1. With Tail selected, observe the event timestamps
|
||||||
|
2. **Expected:** Events are ordered newest-first (descending `created_at`)
|
||||||
|
3. **Expected:** First event shown is from the latest pipeline stage (e.g., stage5_synthesis complete)
|
||||||
|
|
||||||
|
### Test 3: Head Mode Shows Oldest First
|
||||||
|
1. Click the "Head" button
|
||||||
|
2. **Expected:** Head button becomes active, Tail becomes inactive
|
||||||
|
3. **Expected:** Events reorder to oldest-first (ascending `created_at`)
|
||||||
|
4. **Expected:** First event shown is from the earliest pipeline stage (e.g., stage2_segmentation start)
|
||||||
|
|
||||||
|
### Test 4: Mode Switch Resets Pagination
|
||||||
|
1. In Tail mode, click "Next" to advance to page 2+
|
||||||
|
2. Click "Head" button
|
||||||
|
3. **Expected:** View jumps back to page 1 (offset resets to 0)
|
||||||
|
4. **Expected:** Events shown are the first page of oldest-first results
|
||||||
|
|
||||||
|
### Test 5: Pagination Works in Both Modes
|
||||||
|
1. In Head mode, click Next/Prev to page through events
|
||||||
|
2. **Expected:** Pagination works correctly — Next advances, Prev goes back
|
||||||
|
3. Switch to Tail mode, repeat
|
||||||
|
4. **Expected:** Same pagination behavior in Tail mode
|
||||||
|
|
||||||
|
### Test 6: Token Counts Visible
|
||||||
|
1. In either mode, look at event rows with `event_type: llm_call`
|
||||||
|
2. **Expected:** Token counts (prompt_tokens, completion_tokens, total_tokens) displayed on the row
|
||||||
|
3. Look at the video summary row
|
||||||
|
4. **Expected:** Aggregate token count visible per video
|
||||||
|
|
||||||
|
### Test 7: API — Invalid Order Parameter
|
||||||
|
1. Run: `curl -s -w '\n%{http_code}' 'http://ub01:8096/api/v1/admin/pipeline/events/{video_id}?order=invalid'`
|
||||||
|
2. **Expected:** HTTP 400 response
|
||||||
|
|
||||||
|
### Test 8: API — Backward Compatibility
|
||||||
|
1. Run: `curl -sf 'http://ub01:8096/api/v1/admin/pipeline/events/{video_id}?limit=3' | python3 -m json.tool`
|
||||||
|
2. **Expected:** Returns events in descending order (same as `?order=desc`) — no breaking change for callers omitting the parameter
|
||||||
24
.gsd/milestones/M006/slices/S02/tasks/T02-VERIFY.json
Normal file
24
.gsd/milestones/M006/slices/S02/tasks/T02-VERIFY.json
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"taskId": "T02",
|
||||||
|
"unitId": "M006/S02/T02",
|
||||||
|
"timestamp": 1774869322092,
|
||||||
|
"passed": false,
|
||||||
|
"discoverySource": "task-plan",
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"command": "cd frontend",
|
||||||
|
"exitCode": 0,
|
||||||
|
"durationMs": 6,
|
||||||
|
"verdict": "pass"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "npm run build exits 0 with no TypeScript errors",
|
||||||
|
"exitCode": 254,
|
||||||
|
"durationMs": 89,
|
||||||
|
"verdict": "fail"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"retryAttempt": 1,
|
||||||
|
"maxRetries": 2
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,30 @@
|
||||||
# S03: Git Commit SHA in Pipeline Version Metadata
|
# S03: Git Commit SHA in Pipeline Version Metadata
|
||||||
|
|
||||||
**Goal:** Record git commit SHA in pipeline metadata for traceability of prompt/code state at synthesis time
|
**Goal:** Pipeline captures the current git commit SHA at Docker build time, includes it in pipeline version metadata, and the frontend displays it in the version metadata panel.
|
||||||
**Demo:** After this: Running the pipeline captures the current git commit SHA. Viewing a technique page version shows the commit hash in the metadata panel.
|
**Demo:** After this: Running the pipeline captures the current git commit SHA. Viewing a technique page version shows the commit hash in the metadata panel.
|
||||||
|
|
||||||
## Tasks
|
## Tasks
|
||||||
|
- [x] **T01: Added GIT_COMMIT_SHA build arg to Dockerfile.api, compose build args for api/worker, config field, and _get_git_commit_sha() helper — pipeline metadata now includes git_commit_sha key** — Add GIT_COMMIT_SHA build arg to Dockerfile.api, pass it from docker-compose.yml, write it to /app/.git-commit. Add a helper function in stages.py that reads the SHA from the file (Docker) or runs `git rev-parse --short HEAD` (local dev) with fallback to "unknown". Extend `_capture_pipeline_metadata()` to include the `git_commit_sha` key. Add `git_commit_sha` setting to config.py as an additional fallback.
|
||||||
|
|
||||||
|
**Important context for executor:** The canonical codebase is on ub01 at `/vmPool/r/repos/xpltdco/chrysopedia`. SSH with `ssh ub01` to edit files and test. The Docker compose stack runs there. The local working directory has .gsd/ planning artifacts only.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1. SSH to ub01, edit `docker/Dockerfile.api` — add `ARG GIT_COMMIT_SHA=unknown` and `RUN echo "${GIT_COMMIT_SHA}" > /app/.git-commit` after the `COPY backend/ /app/` line
|
||||||
|
2. Edit `docker-compose.yml` — add `args: GIT_COMMIT_SHA: ${GIT_COMMIT_SHA:-unknown}` to both `chrysopedia-api` and `chrysopedia-worker` build sections (they already have `build: context: . dockerfile: docker/Dockerfile.api`)
|
||||||
|
3. Edit `backend/config.py` — add `git_commit_sha: str = "unknown"` field to Settings class
|
||||||
|
4. Edit `backend/pipeline/stages.py` — add `_get_git_commit_sha()` helper that tries: (a) read `/app/.git-commit` file, (b) run `subprocess.run(['git', 'rev-parse', '--short', 'HEAD'])`, (c) return `get_settings().git_commit_sha`, (d) return `"unknown"`. Add `"git_commit_sha": _get_git_commit_sha()` to the dict returned by `_capture_pipeline_metadata()`
|
||||||
|
5. Verify: run `python -c "from pipeline.stages import _capture_pipeline_metadata; print(_capture_pipeline_metadata())"` from backend dir (should show git_commit_sha key)
|
||||||
|
- Estimate: 30m
|
||||||
|
- Files: docker/Dockerfile.api, docker-compose.yml, backend/config.py, backend/pipeline/stages.py
|
||||||
|
- Verify: ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia/backend && python -c "from pipeline.stages import _capture_pipeline_metadata; import json; m = _capture_pipeline_metadata(); assert \"git_commit_sha\" in m, f\"missing key: {m.keys()}\"; print(json.dumps(m, indent=2))"'
|
||||||
|
- [ ] **T02: Display commit SHA in frontend version metadata panel** — Add a conditional render of `git_commit_sha` in the version metadata panel on TechniquePage.tsx. The panel already renders model, captured_at, and prompt_hashes — add a new item for the commit hash using monospace font.
|
||||||
|
|
||||||
|
**Important context for executor:** The canonical codebase is on ub01 at `/vmPool/r/repos/xpltdco/chrysopedia`. SSH with `ssh ub01` to edit files and build. The frontend is at `frontend/` in that repo.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1. SSH to ub01, read `frontend/src/pages/TechniquePage.tsx` lines 315-365 to see existing metadata panel structure
|
||||||
|
2. After the `prompt_hashes` conditional block (around line 358) and before the closing `</div>` of `version-metadata__grid`, add a new conditional block checking `"git_commit_sha" in versionDetail.pipeline_metadata`. Render it as a `version-metadata__item` with key label "Commit" and value in a `<code>` element with monospace font styling (reuse existing `version-metadata__hash-value` class or apply inline). Show first 7 chars: `String(versionDetail.pipeline_metadata.git_commit_sha).slice(0, 7)`
|
||||||
|
3. Run `cd frontend && npm run build` to verify zero TypeScript errors
|
||||||
|
- Estimate: 15m
|
||||||
|
- Files: frontend/src/pages/TechniquePage.tsx
|
||||||
|
- Verify: ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia/frontend && npm run build 2>&1 | tail -5'
|
||||||
|
|
|
||||||
107
.gsd/milestones/M006/slices/S03/S03-RESEARCH.md
Normal file
107
.gsd/milestones/M006/slices/S03/S03-RESEARCH.md
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
# S03 Research: Git Commit SHA in Pipeline Version Metadata
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Straightforward slice. The version metadata infrastructure already exists — `TechniquePageVersion.pipeline_metadata` is a JSONB column, `_capture_pipeline_metadata()` in `stages.py` builds the dict, and the frontend already renders a metadata panel for historical versions. The work is: (1) capture the git commit SHA at Docker build time, (2) inject it into `_capture_pipeline_metadata()`, and (3) add a commit hash display row in the frontend metadata panel.
|
||||||
|
|
||||||
|
The only non-trivial aspect: no `.git` directory exists inside the Docker container, so `git rev-parse HEAD` can't run at runtime inside the worker. The SHA must be baked in at build time.
|
||||||
|
|
||||||
|
## Recommendation
|
||||||
|
|
||||||
|
Use a Docker build arg (`GIT_COMMIT_SHA`) written to a file (`/app/.git-commit`) during image build. The `_capture_pipeline_metadata()` function reads this file. The `docker-compose.yml` passes the arg using shell command substitution. Fallback to `"unknown"` when the file is missing (local dev without Docker).
|
||||||
|
|
||||||
|
Three tasks:
|
||||||
|
1. **Dockerfile + compose** — add build arg, write SHA to file
|
||||||
|
2. **Backend** — read SHA file, add to `_capture_pipeline_metadata()` return dict
|
||||||
|
3. **Frontend** — add commit hash display in the version metadata panel
|
||||||
|
|
||||||
|
## Implementation Landscape
|
||||||
|
|
||||||
|
### Backend — `_capture_pipeline_metadata()` (pipeline/stages.py, lines 557–601)
|
||||||
|
|
||||||
|
Currently returns:
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"models": { "stage2": ..., "stage3": ..., "stage4": ..., "stage5": ..., "embedding": ... },
|
||||||
|
"modalities": { "stage2": ..., "stage3": ..., "stage4": ..., "stage5": ... },
|
||||||
|
"prompt_hashes": { "stage2_segmentation.txt": ..., ... },
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Add `"git_commit_sha": "<sha>"` to this dict. Read from `/app/.git-commit` (Docker) or attempt `git rev-parse --short HEAD` as fallback (local dev). Use a helper function with error suppression — if neither works, return `"unknown"`.
|
||||||
|
|
||||||
|
**No DB migration needed.** `pipeline_metadata` is JSONB — adding a new key is purely a code change.
|
||||||
|
|
||||||
|
### Docker — `docker/Dockerfile.api`
|
||||||
|
|
||||||
|
Add:
|
||||||
|
```dockerfile
|
||||||
|
ARG GIT_COMMIT_SHA=unknown
|
||||||
|
RUN echo "${GIT_COMMIT_SHA}" > /app/.git-commit
|
||||||
|
```
|
||||||
|
|
||||||
|
Place after the `COPY backend/ /app/` line so it doesn't bust the cache for code changes.
|
||||||
|
|
||||||
|
### Docker Compose — `docker-compose.yml`
|
||||||
|
|
||||||
|
Add build arg to both `chrysopedia-api` and `chrysopedia-worker` services (they share the same Dockerfile):
|
||||||
|
```yaml
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/Dockerfile.api
|
||||||
|
args:
|
||||||
|
GIT_COMMIT_SHA: ${GIT_COMMIT_SHA:-unknown}
|
||||||
|
```
|
||||||
|
|
||||||
|
At build time, invoke with:
|
||||||
|
```bash
|
||||||
|
GIT_COMMIT_SHA=$(git rev-parse --short HEAD) docker compose build
|
||||||
|
```
|
||||||
|
|
||||||
|
Or export `GIT_COMMIT_SHA` before building. The `:-unknown` default means builds without the env var still succeed.
|
||||||
|
|
||||||
|
### Config — `backend/config.py`
|
||||||
|
|
||||||
|
Add `git_commit_sha: str = "unknown"` to Settings. This allows overriding via env var as an alternative to the file-based approach (useful for local dev). The `_capture_pipeline_metadata()` helper should check the file first, then fall back to `settings.git_commit_sha`, then `"unknown"`.
|
||||||
|
|
||||||
|
### Frontend — `frontend/src/pages/TechniquePage.tsx` (lines 316–360)
|
||||||
|
|
||||||
|
The version metadata panel currently checks for `"model"`, `"captured_at"`, and `"prompt_hashes"` keys. Add a check for `"git_commit_sha"`:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
{"git_commit_sha" in versionDetail.pipeline_metadata && (
|
||||||
|
<div className="version-metadata__item">
|
||||||
|
<span className="version-metadata__key">Commit</span>
|
||||||
|
<code className="version-metadata__value" style={{ fontFamily: '"SF Mono", "Fira Code", monospace' }}>
|
||||||
|
{String(versionDetail.pipeline_metadata.git_commit_sha).slice(0, 7)}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
```
|
||||||
|
|
||||||
|
Uses the existing `version-metadata__item` CSS classes — no new styles needed. The monospace font from `version-metadata__hash-value` class can be reused or applied inline.
|
||||||
|
|
||||||
|
### Frontend note — existing metadata key mismatch
|
||||||
|
|
||||||
|
The backend sends `"models"` (plural, a dict of per-stage models) but the frontend checks for `"model"` (singular). This means the "Model" row in the metadata panel never actually renders with current data. This is a pre-existing bug — not in scope for this slice, but the planner should be aware.
|
||||||
|
|
||||||
|
### Verification approach
|
||||||
|
|
||||||
|
1. **Unit**: Run `_capture_pipeline_metadata()` locally → confirm `git_commit_sha` key present
|
||||||
|
2. **Docker build**: `docker compose build` with `GIT_COMMIT_SHA` arg → `docker exec chrysopedia-api cat /app/.git-commit` shows the SHA
|
||||||
|
3. **Frontend**: Navigate to a technique page with versions → switch to a historical version → confirm commit hash appears in metadata panel
|
||||||
|
4. **TypeScript**: `npm run build` in frontend → zero errors
|
||||||
|
|
||||||
|
### File inventory
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|------|--------|
|
||||||
|
| `docker/Dockerfile.api` | Add `ARG GIT_COMMIT_SHA` + `RUN echo` |
|
||||||
|
| `docker-compose.yml` | Add `args:` block to api and worker build sections |
|
||||||
|
| `backend/config.py` | Add `git_commit_sha` setting |
|
||||||
|
| `backend/pipeline/stages.py` | Add SHA reading helper, extend `_capture_pipeline_metadata()` |
|
||||||
|
| `frontend/src/pages/TechniquePage.tsx` | Add commit hash display in metadata panel |
|
||||||
|
|
||||||
|
### Risk
|
||||||
|
|
||||||
|
Low. No schema changes. No new dependencies. The JSONB column accepts any dict shape. The frontend change is additive (conditional render of a new key). Docker build arg has a safe default.
|
||||||
36
.gsd/milestones/M006/slices/S03/tasks/T01-PLAN.md
Normal file
36
.gsd/milestones/M006/slices/S03/tasks/T01-PLAN.md
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
estimated_steps: 8
|
||||||
|
estimated_files: 4
|
||||||
|
skills_used: []
|
||||||
|
---
|
||||||
|
|
||||||
|
# T01: Capture git commit SHA in Docker build and pipeline metadata
|
||||||
|
|
||||||
|
Add GIT_COMMIT_SHA build arg to Dockerfile.api, pass it from docker-compose.yml, write it to /app/.git-commit. Add a helper function in stages.py that reads the SHA from the file (Docker) or runs `git rev-parse --short HEAD` (local dev) with fallback to "unknown". Extend `_capture_pipeline_metadata()` to include the `git_commit_sha` key. Add `git_commit_sha` setting to config.py as an additional fallback.
|
||||||
|
|
||||||
|
**Important context for executor:** The canonical codebase is on ub01 at `/vmPool/r/repos/xpltdco/chrysopedia`. SSH with `ssh ub01` to edit files and test. The Docker compose stack runs there. The local working directory has .gsd/ planning artifacts only.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1. SSH to ub01, edit `docker/Dockerfile.api` — add `ARG GIT_COMMIT_SHA=unknown` and `RUN echo "${GIT_COMMIT_SHA}" > /app/.git-commit` after the `COPY backend/ /app/` line
|
||||||
|
2. Edit `docker-compose.yml` — add `args: GIT_COMMIT_SHA: ${GIT_COMMIT_SHA:-unknown}` to both `chrysopedia-api` and `chrysopedia-worker` build sections (they already have `build: context: . dockerfile: docker/Dockerfile.api`)
|
||||||
|
3. Edit `backend/config.py` — add `git_commit_sha: str = "unknown"` field to Settings class
|
||||||
|
4. Edit `backend/pipeline/stages.py` — add `_get_git_commit_sha()` helper that tries: (a) read `/app/.git-commit` file, (b) run `subprocess.run(['git', 'rev-parse', '--short', 'HEAD'])`, (c) return `get_settings().git_commit_sha`, (d) return `"unknown"`. Add `"git_commit_sha": _get_git_commit_sha()` to the dict returned by `_capture_pipeline_metadata()`
|
||||||
|
5. Verify: run `python -c "from pipeline.stages import _capture_pipeline_metadata; print(_capture_pipeline_metadata())"` from backend dir (should show git_commit_sha key)
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- ``docker/Dockerfile.api` — existing Dockerfile to add build arg to`
|
||||||
|
- ``docker-compose.yml` — existing compose file to add build args to api and worker services`
|
||||||
|
- ``backend/config.py` — existing Settings class to add git_commit_sha field`
|
||||||
|
- ``backend/pipeline/stages.py` — existing `_capture_pipeline_metadata()` function (line 557) to extend`
|
||||||
|
|
||||||
|
## Expected Output
|
||||||
|
|
||||||
|
- ``docker/Dockerfile.api` — contains ARG GIT_COMMIT_SHA and RUN echo to .git-commit`
|
||||||
|
- ``docker-compose.yml` — api and worker services have GIT_COMMIT_SHA build arg`
|
||||||
|
- ``backend/config.py` — Settings has git_commit_sha field`
|
||||||
|
- ``backend/pipeline/stages.py` — `_get_git_commit_sha()` helper added, `_capture_pipeline_metadata()` returns git_commit_sha key`
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia/backend && python -c "from pipeline.stages import _capture_pipeline_metadata; import json; m = _capture_pipeline_metadata(); assert \"git_commit_sha\" in m, f\"missing key: {m.keys()}\"; print(json.dumps(m, indent=2))"'
|
||||||
81
.gsd/milestones/M006/slices/S03/tasks/T01-SUMMARY.md
Normal file
81
.gsd/milestones/M006/slices/S03/tasks/T01-SUMMARY.md
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
---
|
||||||
|
id: T01
|
||||||
|
parent: S03
|
||||||
|
milestone: M006
|
||||||
|
provides: []
|
||||||
|
requires: []
|
||||||
|
affects: []
|
||||||
|
key_files: ["docker/Dockerfile.api", "docker-compose.yml", "backend/config.py", "backend/pipeline/stages.py"]
|
||||||
|
key_decisions: ["Resolution order for git SHA: .git-commit file → git rev-parse → config/env → unknown"]
|
||||||
|
patterns_established: []
|
||||||
|
drill_down_paths: []
|
||||||
|
observability_surfaces: []
|
||||||
|
duration: ""
|
||||||
|
verification_result: "Ran _capture_pipeline_metadata() inside chrysopedia-api container — assertion passed, git_commit_sha key present with expected "unknown" fallback value. Also verified _get_git_commit_sha() standalone returns "unknown" in container (no .git-commit file, no git binary)."
|
||||||
|
completed_at: 2026-03-30T11:24:18.222Z
|
||||||
|
blocker_discovered: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# T01: Added GIT_COMMIT_SHA build arg to Dockerfile.api, compose build args for api/worker, config field, and _get_git_commit_sha() helper — pipeline metadata now includes git_commit_sha key
|
||||||
|
|
||||||
|
> Added GIT_COMMIT_SHA build arg to Dockerfile.api, compose build args for api/worker, config field, and _get_git_commit_sha() helper — pipeline metadata now includes git_commit_sha key
|
||||||
|
|
||||||
|
## What Happened
|
||||||
|
---
|
||||||
|
id: T01
|
||||||
|
parent: S03
|
||||||
|
milestone: M006
|
||||||
|
key_files:
|
||||||
|
- docker/Dockerfile.api
|
||||||
|
- docker-compose.yml
|
||||||
|
- backend/config.py
|
||||||
|
- backend/pipeline/stages.py
|
||||||
|
key_decisions:
|
||||||
|
- Resolution order for git SHA: .git-commit file → git rev-parse → config/env → unknown
|
||||||
|
duration: ""
|
||||||
|
verification_result: passed
|
||||||
|
completed_at: 2026-03-30T11:24:18.223Z
|
||||||
|
blocker_discovered: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# T01: Added GIT_COMMIT_SHA build arg to Dockerfile.api, compose build args for api/worker, config field, and _get_git_commit_sha() helper — pipeline metadata now includes git_commit_sha key
|
||||||
|
|
||||||
|
**Added GIT_COMMIT_SHA build arg to Dockerfile.api, compose build args for api/worker, config field, and _get_git_commit_sha() helper — pipeline metadata now includes git_commit_sha key**
|
||||||
|
|
||||||
|
## What Happened
|
||||||
|
|
||||||
|
Edited four files on ub01: Dockerfile.api (ARG + RUN echo to .git-commit), docker-compose.yml (build args for api and worker), config.py (git_commit_sha Settings field), and stages.py (_get_git_commit_sha() helper with 4-tier fallback + git_commit_sha in _capture_pipeline_metadata() return dict). Verified by copying updated files into running container and confirming git_commit_sha key is present in metadata output.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Ran _capture_pipeline_metadata() inside chrysopedia-api container — assertion passed, git_commit_sha key present with expected "unknown" fallback value. Also verified _get_git_commit_sha() standalone returns "unknown" in container (no .git-commit file, no git binary).
|
||||||
|
|
||||||
|
## Verification Evidence
|
||||||
|
|
||||||
|
| # | Command | Exit Code | Verdict | Duration |
|
||||||
|
|---|---------|-----------|---------|----------|
|
||||||
|
| 1 | `docker exec chrysopedia-api python -c "from pipeline.stages import _capture_pipeline_metadata; import json; m = _capture_pipeline_metadata(); assert 'git_commit_sha' in m; print(json.dumps(m, indent=2))"` | 0 | ✅ pass | 3000ms |
|
||||||
|
| 2 | `docker exec chrysopedia-api python -c "from pipeline.stages import _get_git_commit_sha; print(repr(_get_git_commit_sha()))"` | 0 | ✅ pass | 2000ms |
|
||||||
|
|
||||||
|
|
||||||
|
## Deviations
|
||||||
|
|
||||||
|
Verification ran inside Docker container instead of directly on host because Celery deps aren't installed on host Python.
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
|
||||||
|
Running containers still use old image — need docker compose build to bake SHA into .git-commit. Expected; rebuild happens after slice completes.
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `docker/Dockerfile.api`
|
||||||
|
- `docker-compose.yml`
|
||||||
|
- `backend/config.py`
|
||||||
|
- `backend/pipeline/stages.py`
|
||||||
|
|
||||||
|
|
||||||
|
## Deviations
|
||||||
|
Verification ran inside Docker container instead of directly on host because Celery deps aren't installed on host Python.
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
Running containers still use old image — need docker compose build to bake SHA into .git-commit. Expected; rebuild happens after slice completes.
|
||||||
29
.gsd/milestones/M006/slices/S03/tasks/T02-PLAN.md
Normal file
29
.gsd/milestones/M006/slices/S03/tasks/T02-PLAN.md
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
estimated_steps: 6
|
||||||
|
estimated_files: 1
|
||||||
|
skills_used: []
|
||||||
|
---
|
||||||
|
|
||||||
|
# T02: Display commit SHA in frontend version metadata panel
|
||||||
|
|
||||||
|
Add a conditional render of `git_commit_sha` in the version metadata panel on TechniquePage.tsx. The panel already renders model, captured_at, and prompt_hashes — add a new item for the commit hash using monospace font.
|
||||||
|
|
||||||
|
**Important context for executor:** The canonical codebase is on ub01 at `/vmPool/r/repos/xpltdco/chrysopedia`. SSH with `ssh ub01` to edit files and build. The frontend is at `frontend/` in that repo.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1. SSH to ub01, read `frontend/src/pages/TechniquePage.tsx` lines 315-365 to see existing metadata panel structure
|
||||||
|
2. After the `prompt_hashes` conditional block (around line 358) and before the closing `</div>` of `version-metadata__grid`, add a new conditional block checking `"git_commit_sha" in versionDetail.pipeline_metadata`. Render it as a `version-metadata__item` with key label "Commit" and value in a `<code>` element with monospace font styling (reuse existing `version-metadata__hash-value` class or apply inline). Show first 7 chars: `String(versionDetail.pipeline_metadata.git_commit_sha).slice(0, 7)`
|
||||||
|
3. Run `cd frontend && npm run build` to verify zero TypeScript errors
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- ``frontend/src/pages/TechniquePage.tsx` — existing version metadata panel (lines 315-365)`
|
||||||
|
- ``backend/pipeline/stages.py` — T01 output confirming `git_commit_sha` key name in pipeline_metadata dict`
|
||||||
|
|
||||||
|
## Expected Output
|
||||||
|
|
||||||
|
- ``frontend/src/pages/TechniquePage.tsx` — version metadata panel includes conditional render of git_commit_sha as "Commit" row with monospace-styled 7-char hash`
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia/frontend && npm run build 2>&1 | tail -5'
|
||||||
Loading…
Add table
Reference in a new issue