Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ The project uses [Trivy](https://github.com/aquasecurity/trivy) for automated co
To run Trivy locally before pushing:
```bash
# Scan the production Docker image
docker build -t eventrelay:test -f Dockerfile.production .
docker build -t eventrelay:test -f infrastructure/docker/Dockerfile.production .
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasecurity/trivy:latest image eventrelay:test
```

Expand Down
1 change: 1 addition & 0 deletions apps/web/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const nextConfig = {
root: path.resolve(__dirname, '../..'),
},
images: {
formats: ['image/avif', 'image/webp'],
remotePatterns: [
{ protocol: 'https', hostname: 'uvai.io' },
{ protocol: 'https', hostname: 'api.uvai.io' },
Expand Down
7 changes: 5 additions & 2 deletions apps/web/src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ const DashboardSplitView = dynamic(
// ============================================
function VideoCard({
video,
priority = false,
onClick
}: {
video: Video;
priority?: boolean;
onClick: () => void;
}) {
return (
Expand All @@ -49,6 +51,7 @@ function VideoCard({
src={video.thumbnail}
alt={video.title}
fill
priority={priority}
className="object-cover transition-transform duration-500 group-hover:scale-105"
sizes="(max-width: 768px) 100vw, 33vw"
/>
Expand Down Expand Up @@ -296,8 +299,8 @@ function DashboardContent() {
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredVideos.map((video) => (
<VideoCard key={video.id} video={video} onClick={() => selectVideo(video.id)} />
{filteredVideos.map((video, index) => (
<VideoCard key={video.id} video={video} priority={index === 0} onClick={() => selectVideo(video.id)} />
))}
</div>
)}
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ export default function RootLayout({
<html lang="en">
<head>
<StructuredData />
<link rel="preconnect" href="https://img.youtube.com" crossOrigin="anonymous" />
<link rel="preconnect" href="https://i.ytimg.com" crossOrigin="anonymous" />
</head>
<body
className={`${inter.variable} ${jetBrainsMono.variable} ${spaceGrotesk.variable} min-h-screen bg-surface-950 font-sans antialiased`}
Expand Down
3 changes: 2 additions & 1 deletion apps/web/src/components/VideoWorkflowStudio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,8 @@ export default function VideoWorkflowStudio() {
alt={`Source frame ${index + 1}`}
width={320}
height={180}
loading="lazy"
loading={index === 0 ? 'eager' : 'lazy'}
fetchPriority={index === 0 ? 'high' : 'auto'}
className="h-full w-full object-cover"
/>
) : (
Expand Down
108 changes: 108 additions & 0 deletions docs/pr-remediation/2026-07-31-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# PR Remediation & Publish Run — 2026-07-31

Automated execution of the PR Remediation & Publish Runbook against
`groupthinking/EventRelay`. GitHub surface: GitHub MCP (PR read + comment +
merge available). Oldest-first scan of all open PRs, each driven to a terminal
state per the runbook's Definition of Done (`MERGED` / `DEFERRED` / `HALTED`).

## Headline finding

**No open PR has an autonomous merge path.** All 30 open PRs are drafts. Every
substantive PR passes functional CI (CI, Coverage, CodeQL, Security Scan, Secret
Scan, Dependency Review) but is **deliberately held draft** and fails the
repo-defined `agent-completion/truth-gate/pr-<n>` governance check. The gate's
failure reasons are human-only: `draft_pr`, `missing_agent_result`,
`missing_copilot_current_head_review`, `scope_drift`, `unresolved_review`, and an
unmanufacturable historical *provenance disposition*. Several gate runs also error
on `invalid_payload` (the gate workflow itself faulting, not evaluating rules).

The PR bodies state this explicitly, e.g. #734 / #810 / #831: *"cannot be
retroactively manufactured by the connected `groupthinking` controller … Keep
draft pending an authorized legacy disposition … Final human review."*

Consequences for an automated runbook:

- **SCOPE GATE** (runbook §3.2): draft → `DEFERRED`. Applies to all 30.
- **PUBLISH GATE** (runbook §3.8): human by default; `auto_merge_policy` is
unset → conservative → no auto-merge to protected `main`.
- **CodeRabbit loop** (runbook §4) is a **no-op** here: CodeRabbit reports
`Review skipped: excluded by label configuration` on these PRs.
- Pushing commits or running review loops would **destroy the exact-head
evidence** each PR has assembled and would **not** touch the actual blocker
(human provenance disposition + final human review).

Therefore no merge, commit, or review-loop action was taken against any PR. The
only remaining work is human — this run cannot advance it.

## Terminal states (oldest first)

| PR | Author | Title | CI (functional) | Truth-gate | Draft | Terminal state |
|----|--------|-------|-----------------|-----------|-------|----------------|
| 734 | groupthinking | fix(security): pin cloud callbacks vs DNS rebinding | green | fail: draft/provenance | yes | HALTED(human: provenance + review) |
| 810 | groupthinking | fix(security): sanitize API logs (CWE-117) | green | fail: draft/provenance | yes | HALTED(human: provenance + review) |
| 831 | groupthinking | fix(security): restore CWE-209 protections | green | fail: draft/provenance | yes | HALTED(human: provenance + review) |
| 869 | groupthinking | fix: harden API-cost webhook outbox (MYX-79) | CodeRabbit approved | fail: scope_drift/provenance | yes | HALTED(human: scope + review) |
| 903 | jules[bot] | fix(auth): restore Google OAuth in Vercel prod | — | fail: scope_drift/provenance | yes | HALTED(human: scope + review) |
| 906 | groupthinking | fix(ci): remediate PR #877 rollout gaps | — | fail: unresolved_review/scope | yes | HALTED(human: review) |
| 961 | jules[bot] | [DRAFT EVIDENCE] duplicate a11y proposal | — | — | yes | DEFERRED(draft, evidence/duplicate) |
| 987 | Copilot | [DRAFT EVIDENCE] unbound CI / module-shadowing | — | — | yes | DEFERRED(draft, evidence) |
| 995 | groupthinking | perf(mcp): reuse pooled aiohttp session | green | fail: invalid_payload | yes | HALTED(human: review; gate faulting) |
| 996 | groupthinking | fix(mcp): actually reuse pooled aiohttp session | — | — | yes | DEFERRED(draft, duplicate of #995) |
| 997 | jules[bot] | ⚡ Bolt: optimize AgentFlowVisualizer layout | — | — | yes | DEFERRED(draft) |
| 999 | dependabot | bump gh-aw-actions/setup 0.82.14→0.83.4 | green | — | yes | DEFERRED(draft; green, mergeable — needs human ready+merge) |
| 1000 | dependabot | bump actions/checkout 4.2.2→7.0.1 | green | — | yes | DEFERRED(draft; green — needs human ready+merge) |
| 1001 | dependabot | bump actions/setup-python 6→7 | **all green** | pass (not_applicable) | yes | DEFERRED(draft; fully green — needs human ready+merge) |
| 1002 | dependabot | bump locust 2.45→2.46 (dev) | green | — | yes | DEFERRED(draft; green — needs human ready+merge) |
| 1003 | dependabot | bump actions/github-script 8→9 | green | — | yes | DEFERRED(draft; green — needs human ready+merge) |
| 1004–1008 | dependabot | bump @opentelemetry/* in apps/web (5 PRs) | green | — | yes | DEFERRED(draft, labeled duplicate; needs human ready+merge) |
| 1020 | jules[bot] | perf: optimize call stacks / string allocs | — | — | yes | DEFERRED(draft) |
| 1022 | jules[bot] | perf(web): optimize bounding box calc | — | — | yes | DEFERRED(draft, duplicate) |
| 1038 | jules[bot] | feat: implement MCPOrchestrator._execute_on_server | green | fail: invalid_payload | yes | DEFERRED(draft, superseded by #1040) |
| 1040 | groupthinking | fix(mcp): green up #1038 E2E tests | green | fail: invalid_payload | yes | HALTED(human: review; gate faulting) |
| 1043 | jules[bot] | perf(web): optimize viewBox computation | — | — | yes | DEFERRED(draft, duplicate) |
| 1044 | groupthinking | docs(triage): PR remediation run 2026-07-27 | — | — | yes | DEFERRED(draft, prior run's report) |
| 1045 | jules[bot] | 🎨 Palette: dashboard focus-visible styling | — | — | yes | DEFERRED(draft, duplicate) |
| 1047 | jules[bot] | ci: suppress failure issues on no-op runs | — | fail: invalid_payload | yes | DEFERRED(draft; gate faulting) |
| 1049 | groupthinking | fix(a11y): dashboard focus contrast + coverage | green | fail: invalid_payload | yes | HALTED(human: review; gate faulting) |

Rows marked "—" under CI were classified categorically from the uniform pattern
confirmed across the directly-inspected sample (734, 810, 831, 869, 903, 906,
995, 1001, 1040, 1047, 1049), not individually re-queried.

## Staged next commands (human)

The blocking gate is human by design. To advance any substantive PR a maintainer must:

1. Provide the truth-gate's *historical provenance disposition* (or relax the gate
for legacy PRs predating their focused issues).
2. Mark the PR ready for review and complete final human review.
3. Merge to protected `main` per branch policy.

Safe fast-path candidates (green CI, low risk, no provenance concern) — **human
mark-ready + merge**, e.g.:

```
# Fully green dependabot bump, truth-gate not-applicable:
# gh pr ready 1001 && gh pr merge 1001 --squash
# Same shape: 999, 1000, 1002, 1003, 1004, 1005, 1006, 1007, 1008
```

## Infrastructure note for maintainers

The `agent-completion/truth-gate` workflow is erroring with `invalid_payload` on
several PRs (#995, #1038, #1040, #1047, #1049) — the gate is faulting rather than
evaluating its rules. Worth a look independent of any single PR, since it blocks
the merge status of otherwise-green PRs.

## Runbook parameters (as run)

```yaml
github_surface: github-mcp # write-capable, confirmed
coderabbit_handle: "@coderabbitai" # no-op here: excluded by label config
auto_merge_policy: unset # → conservative: never auto-merge protected main
merge_method: unset
non_github_hosts: [] # no sub-agent spawn
```

_Terminal-state summary: 0 MERGED, ~17 DEFERRED, ~7 HALTED (all on human gates).
No autonomous merge path exists; remaining work is human-only._
35 changes: 30 additions & 5 deletions infrastructure/docker/Dockerfile.production
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,25 @@ WORKDIR /app
# Copy all files (matches existing Dockerfile pattern)
COPY . /app/

# Install Python packages with SSL trust configuration for constrained environments
# Install Python packages with SSL trust configuration for constrained environments.
#
# Version floors are duplicated from requirements.txt / pyproject.toml rather than
# installed via `-r requirements.txt`, because this image deliberately ships a
# reduced runtime subset. They MUST stay >= the canonical declarations; the
# equivalence is enforced by
# tests/unit/test_security_fixes.py::test_dockerfile_production_pins_dependency_floors.
#
# Failure is fatal by design: a swallowed `pip install` previously let this image
# build successfully with no packages installed, deferring the error to runtime.
RUN pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org \
fastapi uvicorn pytest python-dotenv pydantic aiofiles httpx requests python-multipart || \
echo "Warning: Some packages may not be available in constrained environments"
"fastapi>=0.110.0" \

@vercel vercel Bot Jul 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dockerfile.production omits the slowapi package, so the container crashes at startup with ModuleNotFoundError: No module named 'slowapi' when uvicorn imports youtube_extension.main.

Fix on Vercel

"uvicorn[standard]>=0.24.0" \
"python-dotenv>=1.2.2" \
"pydantic>=2.5.0" \
"aiofiles>=23.2.1" \
"httpx>=0.25.0" \
"requests>=2.31.0" \
"python-multipart>=0.0.31"

# Create necessary directories and set permissions
RUN mkdir -p logs && \
Expand All @@ -43,5 +58,15 @@ USER appuser
# Expose port
EXPOSE 8000

# Start the application (matches existing server pattern)
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
# Start the application.
#
# The application package lives under /app/src and uses absolute imports rooted
# there, so PYTHONPATH must include it -- this is the invocation documented in
# CLAUDE.md (`PYTHONPATH=src uvicorn youtube_extension.main:app`). The former
# `server:app` target referenced a root-level server.py that does not exist in
# this repository, so the container exited immediately on start. The module is
# asserted importable by
# tests/unit/test_security_fixes.py::test_dockerfile_production_entrypoint_module_exists.
ENV PYTHONPATH=/app/src

CMD ["uvicorn", "youtube_extension.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
Loading
Loading