Skip to content

Commit 0c72839

Browse files
authored
Merge branch 'main' into codex/fix-cache-key-comparison-logic
2 parents eee22a4 + 998a5c6 commit 0c72839

File tree

77 files changed

+6483
-394
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+6483
-394
lines changed

.github/workflows/ci.yml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,76 @@ jobs:
102102

103103
- name: Build
104104
run: npm run build
105+
106+
performance-budget:
107+
runs-on: ubuntu-latest
108+
needs:
109+
- frontend-tests
110+
env:
111+
PERF_BUDGET_HEADLESS: 'true'
112+
steps:
113+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
114+
115+
- name: Set up Node.js
116+
uses: actions/setup-node@0a44ba78451273a1ed8ac2fee4e347c72dfd377f
117+
with:
118+
node-version: '20'
119+
cache: 'npm'
120+
cache-dependency-path: ./frontend/package-lock.json
121+
122+
- name: Install dependencies
123+
working-directory: ./frontend
124+
run: npm ci
125+
126+
- name: Start application stack
127+
run: |
128+
docker compose -f docker-compose.dev.yml up -d --build
129+
130+
- name: Wait for API
131+
run: |
132+
for i in {1..60}; do curl -sf http://localhost:8000/healthcheck && break || sleep 2; done
133+
134+
- name: Wait for Frontend
135+
run: |
136+
for i in {1..60}; do curl -sf http://localhost:3000/models/manifest.json && break || sleep 2; done
137+
138+
- name: Run performance budget checks
139+
working-directory: ./frontend
140+
env:
141+
PERF_BUDGET_OUTPUT_DIR: ../test-results/perf
142+
run: npm run perf:budget
143+
144+
- name: Upload performance budget report
145+
if: always()
146+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
147+
with:
148+
name: perf-budget
149+
path: test-results/perf
150+
151+
- name: Shutdown stack
152+
if: always()
153+
run: |
154+
docker compose -f docker-compose.dev.yml down
155+
156+
observability-budgets:
157+
runs-on: ubuntu-latest
158+
needs:
159+
- performance-budget
160+
steps:
161+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
162+
163+
- name: Set up Python
164+
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c
165+
with:
166+
python-version: '3.12'
167+
168+
- name: Install dependencies
169+
run: pip install pyyaml
170+
171+
- name: Check observability budgets
172+
env:
173+
PROMETHEUS_URL: ${{ secrets.PROMETHEUS_URL }}
174+
PROMETHEUS_BEARER_TOKEN: ${{ secrets.PROMETHEUS_BEARER_TOKEN }}
175+
TEMPO_URL: ${{ secrets.TEMPO_URL }}
176+
TEMPO_BEARER_TOKEN: ${{ secrets.TEMPO_BEARER_TOKEN }}
177+
run: python tools/ci/check_observability_budgets.py --config observability-budgets.yml

.github/workflows/perf-light.yml

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,111 @@ on:
1111
pull_request: {}
1212

1313
jobs:
14+
playwright-budgets:
15+
runs-on: ubuntu-latest
16+
timeout-minutes: 25
17+
steps:
18+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
19+
20+
- name: Use Node.js 20
21+
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
22+
with:
23+
node-version: '20'
24+
cache: 'npm'
25+
cache-dependency-path: frontend/package-lock.json
26+
27+
- name: Install frontend dependencies
28+
working-directory: frontend
29+
run: npm ci
30+
31+
- name: Install Playwright browsers
32+
working-directory: frontend
33+
run: npx playwright install --with-deps chromium
34+
35+
- name: Start stack
36+
run: |
37+
docker compose --env-file .env.development -f docker-compose.dev.yml up -d --build
38+
39+
- name: Wait for API
40+
run: |
41+
for i in {1..60}; do curl -sf http://localhost:8000/healthcheck && break || sleep 2; done
42+
43+
- name: Wait for Frontend
44+
run: |
45+
for i in {1..60}; do curl -sf http://localhost:3000/models/manifest.json && break || sleep 2; done
46+
47+
- name: Seed backend for perf
48+
env:
49+
BASE_URL: http://localhost:8000
50+
run: |
51+
python - <<'PY'
52+
import json
53+
import os
54+
import urllib.error
55+
import urllib.request
56+
57+
BASE_URL = os.environ.get("BASE_URL", "http://localhost:8000")
58+
59+
def post(path: str, payload: dict) -> dict:
60+
req = urllib.request.Request(
61+
f"{BASE_URL}{path}",
62+
data=json.dumps(payload).encode("utf-8"),
63+
headers={"Content-Type": "application/json"},
64+
)
65+
try:
66+
with urllib.request.urlopen(req, timeout=10) as resp:
67+
return json.loads(resp.read().decode("utf-8"))
68+
except urllib.error.HTTPError as exc:
69+
detail = exc.read().decode("utf-8", "ignore")
70+
raise SystemExit(f"Seed request failed ({exc.code}): {detail}")
71+
72+
material = post(
73+
"/api/materials/",
74+
{"name": "Walnut", "texture_url": None, "cost_per_sq_ft": 12.5},
75+
)
76+
material_id = material.get("id")
77+
if not material_id:
78+
raise SystemExit("Material creation failed; missing id")
79+
80+
post(
81+
"/api/modules/",
82+
{
83+
"name": "Base600",
84+
"width": 600.0,
85+
"height": 720.0,
86+
"depth": 580.0,
87+
"base_price": 100.0,
88+
"material_id": material_id,
89+
},
90+
)
91+
PY
92+
93+
- name: Run Playwright performance budgets
94+
env:
95+
PERF_RESULTS_DIR: ${{ github.workspace }}/artifacts/perf
96+
PERF_BUDGET_CONFIG: ${{ github.workspace }}/perf-budget.yml
97+
run: |
98+
mkdir -p artifacts/perf
99+
cd frontend
100+
npm run test:perf -- --output=playwright-report/perf
101+
102+
- name: Convert Playwright metrics to JUnit
103+
run: node tools/perf/metrics-to-junit.mjs artifacts/perf artifacts/perf/perf-metrics.junit.xml
104+
105+
- name: Upload performance artifacts
106+
if: always()
107+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
108+
with:
109+
name: perf-budgets
110+
path: |
111+
artifacts/perf
112+
frontend/playwright-report
113+
114+
- name: Shutdown stack
115+
if: always()
116+
run: |
117+
docker compose --env-file .env.development -f docker-compose.dev.yml down
118+
14119
k6:
15120
runs-on: ubuntu-latest
16121
timeout-minutes: 15
@@ -98,3 +203,28 @@ PY
98203
if: always()
99204
run: |
100205
docker compose --env-file .env.development -f docker-compose.dev.yml down
206+
207+
canary-metrics:
208+
runs-on: ubuntu-latest
209+
needs:
210+
- playwright-budgets
211+
- k6
212+
steps:
213+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
214+
215+
- name: Compare canary metrics against budgets
216+
env:
217+
PROMETHEUS_URL: ${{ secrets.PROMETHEUS_URL }}
218+
TEMPO_URL: ${{ secrets.TEMPO_URL }}
219+
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }}
220+
GITHUB_SHA: ${{ github.sha }}
221+
CANARY_RESULTS_DIR: ${{ github.workspace }}/artifacts/canary
222+
run: |
223+
python tools/perf/check-canary-metrics.py
224+
225+
- name: Upload canary metric report
226+
if: always()
227+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
228+
with:
229+
name: canary-metrics
230+
path: artifacts/canary

.github/workflows/perf.yml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
name: perf
2+
3+
permissions:
4+
contents: read
5+
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.ref }}
8+
cancel-in-progress: true
9+
10+
on:
11+
workflow_dispatch:
12+
13+
jobs:
14+
playwright-perf:
15+
runs-on: ubuntu-latest
16+
timeout-minutes: 60
17+
defaults:
18+
run:
19+
working-directory: ./frontend
20+
steps:
21+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
22+
23+
- name: Set up Node.js
24+
uses: actions/setup-node@0a44ba78451273a1ed8ac2fee4e347c72dfd377f
25+
with:
26+
node-version: '20'
27+
cache: 'npm'
28+
cache-dependency-path: ./frontend/package-lock.json
29+
30+
- name: Install dependencies
31+
run: npm ci
32+
33+
- name: Install Playwright browsers
34+
run: npx playwright install --with-deps
35+
36+
- name: Build application
37+
run: npm run build
38+
39+
- name: Start application
40+
run: |
41+
npm run start -- --hostname 0.0.0.0 --port 3000 &
42+
echo $! > ../.next-server-pid
43+
for i in {1..60}; do
44+
if curl -sSf http://127.0.0.1:3000 > /dev/null; then
45+
break
46+
fi
47+
sleep 2
48+
done
49+
if ! curl -sSf http://127.0.0.1:3000 > /dev/null; then
50+
echo "Application failed to start" >&2
51+
exit 1
52+
fi
53+
54+
- name: Run Playwright perf tests
55+
env:
56+
BASE_URL: http://127.0.0.1:3000
57+
run: npx playwright test --reporter=line,html
58+
59+
- name: Stop application
60+
if: always()
61+
run: |
62+
if [ -f ../.next-server-pid ]; then
63+
kill $(cat ../.next-server-pid) || true
64+
rm -f ../.next-server-pid
65+
fi
66+
67+
- name: Upload Playwright artifacts
68+
if: always()
69+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
70+
with:
71+
name: playwright-perf-artifacts
72+
path: |
73+
frontend/playwright-report
74+
frontend/test-results
75+
if-no-files-found: warn

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ yarn-error.log*
3636
.next/
3737
out/
3838
.cache/
39+
artifacts/
3940

4041
# Env files (keep example)
4142
.env

artifacts/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore

backend/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ docker compose --env-file .env.development -f docker-compose.dev.yml up backend-
2525

2626
The backend expects the following environment variables (or entries in `.env.development`):
2727

28+
- `API_WRITE_TOKEN` – Bearer token required for privileged sync and admin endpoints.
2829
- `HYGRAPH_WEBHOOK_SECRET` – Shared secret used to validate incoming Hygraph webhook signatures.
30+
- `API_WRITE_TOKEN` – Bearer token required for privileged sync endpoints such as `/api/sync/hygraph/pull`.
2931

3032
## Project Structure
3133

0 commit comments

Comments
 (0)