Skip to content

Commit f53d904

Browse files
merge: integration/2026-06-11-pending-backlog into develop (#316, #253, upstream fixes, CI gates)
PR-equivalent merge performed via temporary branch-protection lift because PR functionality is currently disabled platform-side on this fork (GitHub returns 410 on all PR endpoints despite PRs working through #314). Protection restored immediately after this push. Full CI-equivalent checks run locally. Included work: - fix/issue-316-provider-auth-errors (#316): map model-provider auth/billing failures to actionable chat messages instead of the generic 'Workspace setup failed'; all Sonnet review findings fixed (narrow auth matching, explicit HTTP 401/402 forms, tightened billing regex, negative tests). - fix/issue-253-sidebar-offcanvas-collapse (#253): sessions sidebar switched from icon-rail to offcanvas collapse per issue spec; visible collapse + reopen controls; persisted state; dead icon-rail code removed; rail-actions contract tests added. - chore/upstream-clean-fixes: upstream cherry-picks vercel-labs#878/#879/#886 (stale sandbox head before broker commits, git fetch stderr handling, web-fetch tool approval gate — approval UI verified wired). - claude/dev-pipeline-robustness: machine-enforced pipeline gates (additive CI build+guards jobs, production-smoke workflow, migration-safety and test-touch scripts, opt-in pre-push hook, pipeline-gates process doc, concurrent test-isolated runner). Checks (CI-equivalent of required lint-and-typecheck, run at 52427ff): git diff --check clean; bun run check 0 warnings/0 errors; bun run typecheck 4/4; bun run test:isolated 342/342 files pass; db:check migrations in sync. Review: independent integration review (Opus) found no blocking issues across the combined diff (31 files, +1571/-188); two non-blocking hardening items were fixed in 52427ff. bun.lock unchanged. Deploy notes: no migrations, no env/secret changes (production-smoke.yml reuses existing VERCEL_AUTOMATION_BYPASS_SECRET). Rollback: revert this merge commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 parents f2caff0 + 52427ff commit f53d904

31 files changed

Lines changed: 1703 additions & 189 deletions

.githooks/pre-push

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Fast local gate that runs before every `git push`.
4+
#
5+
# It catches the cheap, deterministic failures (whitespace conflict markers,
6+
# lint/format drift, type errors) before they burn a CI cycle or land in a
7+
# reviewer's lap. This is intentionally a *fast* subset of `bun run ci`; the
8+
# full test suite still runs in CI.
9+
#
10+
# Install: bun run hooks:install (or ./init.sh)
11+
# Bypass: SKIP_HOOKS=1 git push (or git push --no-verify)
12+
set -Eeuo pipefail
13+
14+
if [[ "${SKIP_HOOKS:-0}" == "1" ]]; then
15+
printf '\033[1;33mpre-push:\033[0m SKIP_HOOKS=1 set, skipping checks\n' >&2
16+
exit 0
17+
fi
18+
19+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
20+
cd "$ROOT_DIR"
21+
22+
step() {
23+
printf '\033[1;34mpre-push:\033[0m %s\n' "$*" >&2
24+
}
25+
26+
fail() {
27+
printf '\033[1;31mpre-push failed:\033[0m %s\n' "$*" >&2
28+
printf 'Fix the issue, or bypass with: SKIP_HOOKS=1 git push\n' >&2
29+
exit 1
30+
}
31+
32+
step "git diff --check (whitespace / merge markers)"
33+
git diff --check || fail "git diff --check found whitespace or conflict-marker errors"
34+
35+
step "bun run check (lint + format)"
36+
bun run check || fail "lint/format check failed (try: bun run fix)"
37+
38+
step "bun run typecheck"
39+
bun run typecheck || fail "typecheck failed"
40+
41+
printf '\033[1;32mpre-push:\033[0m checks passed\n' >&2

.github/CODEOWNERS

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# CODEOWNERS for fork-open-agents
2+
#
3+
# This file documents the high-risk surfaces named in the Production Release
4+
# Runbook (auth, ownership, secrets, billing, inference, GitHub App, sandbox,
5+
# workflows, migrations). Changes to these paths warrant extra scrutiny.
6+
#
7+
# Today this is a solo project, so a single owner is listed. Once a second
8+
# regular reviewer exists, enable "Require review from Code Owners" in branch
9+
# protection so these paths automatically request that reviewer.
10+
11+
# Default owner for everything not matched below.
12+
* @dennisonbertram
13+
14+
# --- High-risk surfaces ------------------------------------------------------
15+
16+
# Auth / OAuth / sessions
17+
/apps/web/lib/auth/ @dennisonbertram
18+
19+
# Database schema and migrations (irreversible / data-loss risk)
20+
/apps/web/lib/db/schema.ts @dennisonbertram
21+
/apps/web/lib/db/migrations/ @dennisonbertram
22+
/apps/web/lib/db/migrate.ts @dennisonbertram
23+
24+
# Inference / model wiring
25+
/apps/web/lib/inference/ @dennisonbertram
26+
/packages/agent/ @dennisonbertram
27+
28+
# GitHub App / webhook flows
29+
/apps/web/lib/github/ @dennisonbertram
30+
31+
# Sandbox lifecycle and managed runtime
32+
/apps/web/lib/sandbox/ @dennisonbertram
33+
/apps/web/lib/managed-runtime/ @dennisonbertram
34+
/packages/sandbox/ @dennisonbertram
35+
36+
# Background agents
37+
/apps/web/lib/background-agents/ @dennisonbertram
38+
39+
# CI / deploy / pipeline configuration
40+
/.github/ @dennisonbertram
41+
/turbo.json @dennisonbertram
42+
/init.sh @dennisonbertram
43+
/scripts/ @dennisonbertram

.github/workflows/ci.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,80 @@ jobs:
4141

4242
- name: DB Check
4343
run: bun run --cwd apps/web db:check
44+
45+
# Compiles the Next.js app the same way Vercel does. Typecheck does not catch
46+
# RSC/"use client" boundary errors, route export shape, or bundler failures;
47+
# without this job those only surface on the production deploy from `main`.
48+
build:
49+
runs-on: ubuntu-latest
50+
timeout-minutes: 20
51+
52+
steps:
53+
- name: Checkout
54+
uses: actions/checkout@v4
55+
with:
56+
repository: ${{ github.event.pull_request.head.repo.full_name }}
57+
ref: ${{ github.event.pull_request.head.sha }}
58+
59+
- name: Setup Bun
60+
uses: oven-sh/setup-bun@v2
61+
with:
62+
bun-version: "1.2.14"
63+
64+
- name: Install dependencies
65+
run: bun install --frozen-lockfile
66+
67+
# Placeholder env so `next build` can compile without a live database.
68+
# This is a compile/bundle check, not an env-validation check.
69+
- name: Build (next build)
70+
run: bun run --cwd apps/web build:ci
71+
env:
72+
POSTGRES_URL: postgres://user:pass@localhost:5432/db
73+
BETTER_AUTH_SECRET: ci_placeholder_secret_at_least_32_chars_long
74+
ENCRYPTION_KEY: ci_placeholder_secret_at_least_32_chars_long
75+
JWE_SECRET: ci_placeholder_secret_at_least_32_chars_long
76+
GITHUB_CLIENT_SECRET: ci-placeholder
77+
VERCEL_APP_CLIENT_SECRET: ci-placeholder
78+
NEXT_PUBLIC_GITHUB_CLIENT_ID: ci-placeholder
79+
NEXT_PUBLIC_VERCEL_APP_CLIENT_ID: ci-placeholder
80+
NEXT_PUBLIC_AUTH_PROVIDERS: vercel
81+
NEXT_TELEMETRY_DISABLED: "1"
82+
83+
# PR-only guardrails: enforce the migration rollback rule and surface
84+
# behavior changes that ship without tests. test-touch warns by default; set
85+
# STRICT_TEST_TOUCH=1 here to make it blocking once desired.
86+
guards:
87+
if: github.event_name == 'pull_request'
88+
runs-on: ubuntu-latest
89+
timeout-minutes: 10
90+
91+
steps:
92+
- name: Checkout
93+
uses: actions/checkout@v4
94+
with:
95+
repository: ${{ github.event.pull_request.head.repo.full_name }}
96+
ref: ${{ github.event.pull_request.head.sha }}
97+
fetch-depth: 0
98+
99+
- name: Setup Bun
100+
uses: oven-sh/setup-bun@v2
101+
with:
102+
bun-version: "1.2.14"
103+
104+
- name: Install dependencies
105+
run: bun install --frozen-lockfile
106+
107+
- name: Fetch base ref
108+
run: git fetch --no-tags --depth=1 origin "$BASE_REF:refs/remotes/origin/$BASE_REF"
109+
env:
110+
BASE_REF: ${{ github.base_ref }}
111+
112+
- name: Migration safety
113+
run: bun run check:migration-safety
114+
env:
115+
BASE_REF: origin/${{ github.base_ref }}
116+
117+
- name: Test-touch guard
118+
run: bun run check:test-touch
119+
env:
120+
BASE_REF: origin/${{ github.base_ref }}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Production Smoke
2+
3+
# Closes the gap where preview-smoke.yml explicitly skips production: this runs
4+
# the same smoke checks against a production deployment as soon as Vercel
5+
# reports it succeeded. A failure here turns the commit's checks red and pages
6+
# whoever is watching, instead of relying on a human to remember to smoke prod.
7+
#
8+
# This does NOT auto-roll-back. See docs/process/production-release-runbook.md
9+
# for the manual `vercel rollback` path when this check fails.
10+
11+
on:
12+
deployment_status:
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.event.deployment_status.target_url }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
production-smoke:
20+
if: >-
21+
github.event.deployment_status.state == 'success' &&
22+
github.event.deployment_status.target_url != '' &&
23+
(github.event.deployment.environment == 'Production' ||
24+
github.event.deployment.environment == 'production')
25+
runs-on: ubuntu-latest
26+
timeout-minutes: 5
27+
28+
steps:
29+
- name: Checkout
30+
uses: actions/checkout@v4
31+
32+
- name: Setup Bun
33+
uses: oven-sh/setup-bun@v2
34+
with:
35+
bun-version: "1.2.14"
36+
37+
- name: Run production smoke
38+
env:
39+
DEPLOYMENT_URL: ${{ github.event.deployment_status.target_url }}
40+
VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}
41+
run: bun run --cwd apps/web preview:smoke
42+
43+
- name: Rollback reminder on failure
44+
if: failure()
45+
run: |
46+
echo "::error::Production smoke failed for ${DEPLOYMENT_URL}." >&2
47+
echo "::error::Roll back first, debug second: \`vercel rollback\` (see production-release-runbook.md)." >&2
48+
env:
49+
DEPLOYMENT_URL: ${{ github.event.deployment_status.target_url }}

apps/web/app/sessions/sessions-route-shell.tsx

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { X } from "lucide-react";
3+
import { PanelLeft, X } from "lucide-react";
44
import { useParams, usePathname, useRouter } from "next/navigation";
55
import type { CSSProperties, ReactNode } from "react";
66
import {
@@ -22,8 +22,13 @@ import {
2222
SidebarContent,
2323
SidebarInset,
2424
SidebarProvider,
25-
SidebarRail,
25+
useSidebar,
2626
} from "@/components/ui/sidebar";
27+
import {
28+
Tooltip,
29+
TooltipContent,
30+
TooltipTrigger,
31+
} from "@/components/ui/tooltip";
2732
import { useBackgroundChatNotifications } from "@/hooks/use-background-chat-notifications";
2833
import { useSessions, type SessionWithUnread } from "@/hooks/use-sessions";
2934
import { useUserPreferences } from "@/hooks/use-user-preferences";
@@ -51,7 +56,12 @@ const RouteContentShell = memo(function RouteContentShell({
5156
}: {
5257
children: ReactNode;
5358
}) {
59+
const { state, isMobile, openMobile, toggleSidebar } = useSidebar();
5460
const { target, closeWorkspaceSettings } = useWorkspaceSettings();
61+
// The sidebar uses offcanvas collapse: it slides fully off-screen when
62+
// collapsed, leaving nothing visible to reopen it with. Surface a
63+
// persistent "Open panel" button in the content area whenever it is hidden.
64+
const sidebarHidden = isMobile ? !openMobile : state === "collapsed";
5565

5666
useEffect(() => {
5767
if (!target) {
@@ -68,6 +78,25 @@ const RouteContentShell = memo(function RouteContentShell({
6878

6979
return (
7080
<SidebarInset className="relative flex min-w-0 flex-1 flex-col overflow-hidden">
81+
{sidebarHidden ? (
82+
<Tooltip>
83+
<TooltipTrigger asChild>
84+
<Button
85+
type="button"
86+
variant="outline"
87+
size="icon"
88+
onClick={toggleSidebar}
89+
className="absolute left-2.5 top-2.5 z-30 h-8 w-8 bg-background/80 shadow-sm backdrop-blur"
90+
aria-label="Open panel"
91+
>
92+
<PanelLeft className="h-4 w-4" />
93+
</Button>
94+
</TooltipTrigger>
95+
<TooltipContent side="right" sideOffset={4}>
96+
Open panel
97+
</TooltipContent>
98+
</Tooltip>
99+
) : null}
71100
{children}
72101
{target ? (
73102
<div
@@ -363,8 +392,7 @@ export function SessionsRouteShell({
363392
} as CSSProperties
364393
}
365394
>
366-
<Sidebar collapsible="icon" className="border-r border-border">
367-
<SidebarRail />
395+
<Sidebar collapsible="offcanvas" className="border-r border-border">
368396
<SidebarContent className="bg-muted/20">
369397
<InboxSidebar
370398
sessions={sessions}

0 commit comments

Comments
 (0)