Runbook: Set Up Vercel Deployment with Promotion Checks
Runbook State
Production-validated setup procedure.
Purpose
This runbook documents the setup procedure to:
- Connect the
portfolio-apprepository to a Vercel project - Configure environment variables across environments (development, preview, production)
- Set up GitHub Deployment Checks to gate production promotion on CI checks
- Validate end-to-end that preview deployments work and production is gated correctly
This runbook implements the decision in ADR-0007: Host Portfolio App on Vercel with Promotion Gated by GitHub Checks.
Scope
Use when
- First-time Vercel project setup for portfolio-app
- Reconfiguring environment variables or deployment gating
- Troubleshooting promotion checks or preview deployments
Do not use when
- performing routine deployments (see rbk-portfolio-deploy.md)
- rolling back a release (see rbk-portfolio-rollback.md)
- triaging CI failures (see rbk-portfolio-ci-triage.md)
Prereqs / Inputs
Access & Accounts
- Vercel account with permission to create/configure projects
- GitHub account with admin access to
portfolio-apprepository - DNS access (if configuring custom domain; for MVP, skip)
Prerequisites
portfolio-apprepository exists and is public on GitHubportfolio-appis onmainbranch with recent commits- Portfolio Docs App is deployed to Vercel (at least preview access)
- CI workflows in
portfolio-app/.github/workflows/are live and executing
Key constants (from documentation)
| Item | Value | Reference |
|---|---|---|
| Required CI checks | ci / quality, ci / build | CI workflow |
| Environment variables | See Environment Variable Contract (/docs/_meta/env/portfolio-app-env-contract.md) | .env.example in repo |
| Docs base URL (local dev) | http://localhost:3001 | Portfolio Docs local default |
| Documentation repo URL | (URL of portfolio-docs Vercel deployment) | To be determined during setup |
Procedure / Content
Phase 1: Connect portfolio-app to Vercel
Step 1.1: Create or access Vercel project
From Vercel Dashboard:
- Go to vercel.com/dashboard
- Click "Add New" → "Project"
- Select "Import Git Repository"
- Search for and select
bryce-seefieldt/portfolio-app(or your fork) - Click "Import"
If the repo is not listed, ensure:
- Your GitHub account is connected to Vercel (check Settings → Git Integrations)
- The repository is public
Step 1.2: Configure build settings
On the "Import Project" page, configure:
| Setting | Value | Notes |
|---|---|---|
| Framework Preset | Next.js | Auto-detected from next.config.ts |
| Build Command | pnpm build | Uses pnpm (per package.json) |
| Output Directory | .next | Default for Next.js |
| Install Command | pnpm install --frozen-lockfile | Matches CI determinism requirement |
| Node Version | 20.x | Must match .nvmrc in repo |
IMPORTANT: Set Install Command to pnpm install --frozen-lockfile to enforce determinism (matching CI contract in ADR-0008).
Step 1.3: Complete project creation
- Click "Deploy"
- Wait for initial deployment to complete (typically 2–5 minutes)
- After successful deploy, you will see:
- ✅ Preview URL (e.g.,
https://portfolio-app-git-main.vercel.app) - ✅ Production URL (e.g.,
https://portfolio-app.vercel.app)
- ✅ Preview URL (e.g.,
Outcome: Vercel project is connected and initial deployment is complete.
Phase 2: Configure environment variables
Step 2.1: Determine environment variable values
Before configuring Vercel, gather the following URLs:
| Variable | Local Dev | Preview | Production | Example |
|---|---|---|---|---|
NEXT_PUBLIC_DOCS_BASE_URL | http://localhost:3001 | https://portfolio-docs-preview.vercel.app OR https://preview-docs.yourdomain.com | https://docs.yourdomain.com OR https://yourdomain.com/docs | See below |
NEXT_PUBLIC_SITE_URL | (optional) | https://portfolio-app-git-main.vercel.app | https://portfolio.yourdomain.com (if using custom domain) | See below |
NEXT_PUBLIC_GITHUB_URL | (same across environments) | https://github.com/bryce-seefieldt | https://github.com/bryce-seefieldt | — |
NEXT_PUBLIC_LINKEDIN_URL | (same across environments) | https://www.linkedin.com/in/your-handle/ | https://www.linkedin.com/in/your-handle/ | — |
NEXT_PUBLIC_CONTACT_EMAIL | (same across environments) | your-email@example.com | your-email@example.com | — |
For NEXT_PUBLIC_DOCS_BASE_URL, decide your strategy:
Option A: Subdomain (recommended for clarity)
Preview: https://portfolio-docs-git-preview.vercel.app
Production: https://docs.yourdomain.com
Option B: Path-based (simpler DNS)
Production: https://yourdomain.com/docs
For now, use Vercel's default preview URLs and finalize domain strategy later.
Step 2.2: Add environment variables to Vercel
In Vercel Dashboard:
- Open portfolio-app project
- Navigate to Settings → Environment Variables
Add variables with correct environment scope:
Preview (PR branches)
- Click "Add New" for each variable:
| Name | Value | Environment Scope |
|---|---|---|
NEXT_PUBLIC_DOCS_BASE_URL | Portfolio Docs preview URL (e.g., https://portfolio-docs-git-preview.vercel.app) | Preview |
NEXT_PUBLIC_SITE_URL | (leave empty or use Vercel preview URL) | Preview |
NEXT_PUBLIC_GITHUB_URL | Your GitHub profile URL | Preview |
NEXT_PUBLIC_LINKEDIN_URL | Your LinkedIn profile URL | Preview |
NEXT_PUBLIC_CONTACT_EMAIL | Your public contact email | Preview |
Production (main)
- Click "Add New" for each variable:
| Name | Value | Environment Scope |
|---|---|---|
NEXT_PUBLIC_DOCS_BASE_URL | Final docs URL (subdomain or path-based) | Production |
NEXT_PUBLIC_SITE_URL | Your portfolio domain (e.g., https://portfolio.yourdomain.com) | Production |
NEXT_PUBLIC_GITHUB_URL | Your GitHub profile URL | Production |
NEXT_PUBLIC_LINKEDIN_URL | Your LinkedIn profile URL | Production |
NEXT_PUBLIC_CONTACT_EMAIL | Your public contact email | Production |
Deployment Trigger: After adding/modifying environment variables, you must redeploy:
- Go to Deployments tab
- Find the most recent deployment
- Click "…" → "Redeploy"
- Wait for build to complete with new variables
Outcome: Environment variables are configured per scope and deployments will use them on next build.
Phase 3: Set up GitHub Deployment Checks (Production Promotion Gating)
This phase implements the decision in ADR-0007 to gate production promotion on ci / quality and ci / build passing.
Step 3.1: Enable Deployment Checks in Vercel
In Vercel Dashboard:
- Open portfolio-app project
- Navigate to Settings → Git (or Deployments → Git)
- Scroll to "Deployment Checks" section
- Toggle "Enable Deployment Checks" to ON
Step 3.2: Import required GitHub checks
With Deployment Checks enabled, you can now import GitHub checks:
-
Click "Add Check" (or similar button, depending on Vercel UI version)
-
Select "Import from GitHub"
-
Vercel will offer two options:
- "Send workflow updates to Vercel" — Vercel modifies your CI workflow (advanced)
- "Select Checks to Add" — Manually select existing checks (recommended for MVP)
For MVP, choose "Select Checks to Add" (simpler, doesn't modify your workflow)
-
From the list of available checks, select:
- ✅
ci / quality - ✅
ci / build
If checks don't appear immediately:
- Toggle "Show All Checks" switch to ON (Vercel fetches all checks from GitHub)
- Use the "Search for GitHub Checks" field to filter (type
ci / qualityorci / build) - OR enter a GitHub SHA from a recent commit on
main(copy from Commits tab in GitHub)
Note: The SHA is only used to populate the list of available checks. Once you select checks by name, Vercel will monitor those check names on all future commits, not just that specific SHA. You can modify your CI workflow without updating Deployment Checks, as long as the job names (
qualityandbuild) remain the same.After checks appear, select both
ci / qualityandci / build - ✅
-
Set environment scope:
- ✅ Production (so preview deployments are not gated)
-
Click "Save" or "Add Check"
CRITICAL: Ensure both checks are assigned to Production only. Preview deployments should NOT be blocked by these checks (they should run regardless to allow early feedback).
Step 3.3: Verify Vercel Deployment Check configuration
After saving, navigate to Settings → Deployment Checks and verify you see:
ci / quality | production | blocking
ci / build | production | blocking
What these labels mean:
- "production" = Scope – checks only gate production deployments (preview PRs deploy immediately)
- "blocking" = Behavior – production promotion waits until checks pass
Expected behavior:
- ✅ Preview deployments (PRs) → Deploy immediately, checks run in parallel
- ✅ Production deployments (
main) → Blocked until both checks pass - ✅ If either check fails → Production promotion prevented
Outcome: Vercel will now require ci / quality and ci / build to pass before promoting any main branch deployment to production.
Phase 4: Configure GitHub Ruleset (Optional but Recommended)
This phase adds an additional safeguard: GitHub branch protection rules to prevent merge to main if CI checks don't pass.
Step 4.1: Create GitHub Ruleset
In GitHub:
- Navigate to portfolio-app repository
- Go to Settings → Rules → Rulesets
- Click "New ruleset" → "New branch ruleset"
- Configure:
| Setting | Value |
|---|---|
| Ruleset name | main-protection |
| Enforcement | Active |
| Target branches | Targeting rule: Branch name is → main |
Step 4.2: Add required checks to ruleset
- In the ruleset editor, scroll to "Require status checks to pass before merging"
- Click "Add checks"
- Select:
- ✅
ci / quality - ✅
ci / build
- ✅
- Click "Save"
Step 4.3: Additional protections (optional)
Add these for enterprise rigor:
- ✅ Require pull request reviews before merging (Require 1 approval)
- ✅ Dismiss stale pull request approvals when new commits are pushed
- ✅ Block force pushes
- ✅ Block deletions
Outcome: GitHub ruleset prevents merge to main unless CI checks pass and PR is approved.
Phase 5: End-to-End Validation
Step 5.1: Create test PR
From your local environment:
cd portfolio-app
# Create and switch to a test branch
git checkout -b test/vercel-setup
# Make a trivial change (e.g., comment in README)
echo "# Test PR for Vercel setup validation" >> TEST_VERCEL_SETUP.md
# Commit and push
git add TEST_VERCEL_SETUP.md
git commit -m "test: validate Vercel setup with test PR"
git push origin test/vercel-setup
Step 5.2: Open PR and verify GitHub checks run
On GitHub:
- Navigate to portfolio-app → Pull Requests
- Click "New Pull Request"
- Base:
main, Compare:test/vercel-setup - Create PR
Monitor the PR:
- ⏳ Wait 1–2 minutes for GitHub Actions to start
- ✅ Confirm you see checks running:
ci / qualityci / build- CodeQL (optional)
If checks don't appear after 3 minutes, verify:
.github/workflows/ci.ymlexists in repo- Workflow triggers on
pull_requestevent - No syntax errors in workflow file
Step 5.3: Verify Vercel preview deployment
On the PR:
- Scroll to "Deployments" section
- You should see "Vercel" with a preview URL (e.g.,
https://portfolio-app-git-test-*.vercel.app) - Click the preview URL to open the deployment
- Validate:
- ✅ Site loads without errors
- ✅ Navigation works (visit
/cv,/projects,/contact) - ✅ Evidence links in content point to correct docs URL (should match
NEXT_PUBLIC_DOCS_BASE_URLfor preview)
Step 5.4: Verify CI checks pass and GitHub checks are green
On the PR:
- Scroll to "Checks" tab (if available) or look at PR status
- Wait for all checks to complete (typically 5–10 minutes)
- Confirm:
- ✅
ci / quality→ PASS - ✅
ci / build→ PASS - ✅ CodeQL (if configured) → PASS
- ✅
Step 5.5: Attempt merge and verify it succeeds
On the PR:
- Click "Merge pull request" (if green) OR verify the button is enabled
- Select "Squash and merge" or "Create a merge commit"
- Complete the merge
Expected outcome: Merge succeeds because all checks passed.
Step 5.6: Monitor production promotion
After merge:
- Navigate to Vercel → portfolio-app → Deployments
- You should see two deployments:
- A Production deployment (promoted from
main) - The Preview deployment (from the test PR, now closed)
- A Production deployment (promoted from
- Click the Production deployment
- Verify:
- ✅ Status: READY (all checks passed before promotion)
- ✅ Environment variables are set (check Inspection panel)
- ✅ Production URL is live with updated content
Step 5.7: Verify production domain works
Validate production:
- Open the production URL (e.g.,
https://portfolio-app.vercel.app) - Confirm:
- ✅ Site loads
- ✅ Navigation works
- ✅ Evidence links use
NEXT_PUBLIC_DOCS_BASE_URLfor production scope
Outcome: End-to-end validation confirms:
- ✅ Preview deployments work on PRs
- ✅ CI checks gate merge to
main - ✅ Production promotion is automatic after checks pass
- ✅ Environment variables are correct per scope
Phase 6: Configure Staging Domain & Branch Mapping (Stage 4.1)
This phase adds a clear, reviewable staging tier using Vercel's branch/domain mapping while maintaining immutable builds.
Step 6.1: Create a protected staging branch
In GitHub:
- Create
stagingbranch frommain:git checkout main && git pull
git checkout -b staging
git push origin staging - Protect
stagingwith a ruleset similar tomain(optional but recommended):- Require PR reviews
- Require status checks (
ci / quality,ci / build) - Block force pushes and deletions
Step 6.2: Map a staging domain to the staging branch
In Vercel Dashboard:
-
First, add a custom domain to your project:
- Open portfolio-app → Settings → Domains
- Click "Add a domain"
- Enter your staging domain (e.g.,
staging.portfolio.example.com) - Configure DNS according to Vercel's instructions (CNAME or nameserver method)
- Wait for the domain to be verified and assigned to production branch
-
Then, reassign the domain to the
stagingbranch:- In Settings → Domains, locate the staging domain you just added
- Click the "Edit" dropdown next to the domain
- In the modal, find "Connect to an environment" section
- Select "Preview" from the dropdown
- In the "Git Branch" field, enter
staging - Click "Save"
Note: The Domains section in Settings displays your project-level domain assignments. Each domain can be connected to either Production (main branch) or a specific branch in Preview environment.
Result: Deployments from the staging branch will now serve at the staging domain. Commits to other branches will continue to use auto-generated Vercel URLs.
Step 6.3: Environment variable strategy for staging
- Vercel sets
VERCEL_ENV=previewfor non-production deployments (includingstaging). - Keep configuration environment-first using public-safe variables:
NEXT_PUBLIC_SITE_URL→ set to staging domain under Preview scopeNEXT_PUBLIC_DOCS_BASE_URL→ typically production docs; optionally a docs staging domain
- Do not hardcode environments in code. Our helpers treat environment hints as diagnostics only.
Step 6.4: Validate staging deployment
Part A: Trigger staging deployment
- Merge changes to the
stagingbranch (if not already done):git checkout staging
git pull origin staging
git merge main
git push origin staging - Vercel will automatically deploy to the staging domain
- Wait for the deployment to complete (monitor in Vercel dashboard)
Part B: Verify deployment and CI gates pass
Monitor the GitHub Actions CI workflow for the following gates (should all show ✅ PASS):
- Environment validation – Checks that all required env vars are defined
- Required vars:
NEXT_PUBLIC_GITHUB_URL,NEXT_PUBLIC_DOCS_GITHUB_URL,NEXT_PUBLIC_SITE_URL,NEXT_PUBLIC_DOCS_BASE_URL - ⚠️ If this fails: See Troubleshooting section → "CI workflow fails with missing environment variables"
- Required vars:
- Registry check – Verifies build artifacts can be pushed
- Build gate – Compiles the application with
pnpm build - Smoke tests – Runs basic deployment health checks
If any gate fails:
- Click the failed step to view error logs
- See Troubleshooting section at end of runbook for specific errors
- Fix the issue locally, commit, push, and retry the workflow
If all gates pass: Move to Part C
Part C: Verify immutable artifact in Vercel
- Go to your Vercel dashboard: https://vercel.com/dashboard
- Click on portfolio-app project
- Navigate to Deployments tab (top menu)
- Look for a new deployment with:
- Status: "Ready" (green checkmark)
- Branch:
staging - URL: Should be
https://staging-bns-portfolio.vercel.app(or your custom staging domain)
- Click on the deployment to open its details page
- Look for "Commit SHA" (usually shown in the deployment info)
- Note this SHA (e.g.,
f6c1fa8)
- Note this SHA (e.g.,
- Go back to GitHub Actions workflow (from Part B) and find the commit SHA in the logs
- It's typically printed in the workflow summary or build logs
- Verify: Both SHAs should match exactly (this proves the artifact is immutable—same code deployed)
Part D: Validate staging domain
- Open your staging domain in a browser:
https://staging-bns-portfolio.vercel.app - Verify the following:
- Site loads without errors (no blank page or 500 error)
- Navigation works: Click through pages (
/cv,/projects,/contact) - Evidence links resolve: Find a link to portfolio-docs in the content
- Example: "View my architecture" or similar
- Click the link and verify it opens the docs site correctly
- Canonical URL is correct: Open browser DevTools (F12) → Console tab
- Verify no red errors are shown
- Check that
NEXT_PUBLIC_SITE_URLin the page source reflects the staging domain
- Docs base URL is correct: Any
/docslinks should point to your production docs URL- Verify by clicking a docs link and checking the resulting URL
If validation fails:
- Check that environment variables are correctly scoped in Vercel (Settings → Environment Variables)
- Verify DNS is configured if using a custom domain
- See Troubleshooting section
If validation passes: Move to Step 6.5 (Promote to production)
Step 6.5: Promote to production
- Merge staging to main branch:
git checkout main
git pull origin main
git merge staging
git push origin main - Vercel will automatically deploy to production domain
- Verify CI gates pass (env, registry, build, unit + smoke tests)
- Monitor deployment in Vercel dashboard
Outcome: A clear staging tier exists via branch/domain mapping; staging is validated before production deployment.
Phase 7: Clean up and document
Step 6.1: Delete test PR branch
cd portfolio-app
# Delete local branch
git branch -d test/vercel-setup
# Delete remote branch
git push origin --delete test/vercel-setup
Step 6.2: Document your environment
Update the team documentation with your actual URLs:
In portfolio-docs (e.g., update or create a section in deployment.md or a new file):
## Production URLs (2026-01-16)
- **Portfolio App Production:** https://bns-portfolio.vercel.app
- **Portfolio App Staging (Preview):** https://staging-bns-portfolio-vercel.app
- **Portfolio Docs Production:** https://bns-portfolio-docs.vercel.app
- **Portfolio Docs Preview:** https://bns-portfolio-docs-git-\*.vercel.app (dynamic per PR)
### Environment Variables Configured
| Variable | Preview | Production |
| --------------------------- | ------------------------------------------------ | ------------------------------------------------ |
| `NEXT_PUBLIC_DOCS_BASE_URL` | https://bns-portfolio-docs.vercel.app | https://bns-portfolio-docs.vercel.app |
| `NEXT_PUBLIC_SITE_URL` | https://bns-portfolio.vercel.app | https://portfolio.yourdomain.com |
| `NEXT_PUBLIC_GITHUB_URL` | https://github.com/bryce-seefieldt/portfolio-app | https://github.com/bryce-seefieldt/portfolio-app |
| ... | ... | ... |
Step 6.3: Mark deployment as complete
In portfolio-docs dossier:
Update the status line in 03-deployment.md:
Status: Live — CI quality/build gates with frozen installs; **Vercel preview + production promotion with Deployment Checks** (validated 2026-01-16).
Outcome: Production setup is documented and team has a reference for environment URLs and configuration.
Troubleshooting
Vercel waits indefinitely for checks
Symptoms:
- PR preview deploys fine
- Merge to
mainsucceeds - Production deployment stays in "Waiting for checks" state
Root causes & fixes:
-
Checks not running on
pushtomain- Verify
.github/workflows/ci.ymlhaspush: [main]trigger - Check CI workflow logs for failures
- Verify
-
Check names don't match
- Ensure
ci.ymlhas jobs named exactlyqualityandbuild(case-sensitive) - Vercel imports checks as
ci / qualityandci / build
- Ensure
-
Deployment Checks not enabled in Vercel
- Go back to Settings → Git → Deployment Checks and ensure ON
Preview deployment fails but CI checks pass
Root causes:
-
pnpm version mismatch
- Vercel uses specified
packageManagerfrompackage.json - Ensure both CI and Vercel use
pnpm@10.0.0(or same version)
- Vercel uses specified
-
Environment variables missing or incorrect
- Verify
NEXT_PUBLIC_DOCS_BASE_URLis set for Preview scope in Vercel - Check Vercel deployment logs for build errors
- Verify
-
Node version mismatch
- Confirm Vercel uses Node 20.x (set in Settings → Node Version)
Evidence links are broken in preview
Symptoms:
- Links to
/docsreturn 404 in preview
Root causes:
-
NEXT_PUBLIC_DOCS_BASE_URLpoints to wrong URL- For preview, must point to preview docs URL (e.g., portfolio-docs preview on Vercel)
- Check Vercel environment variables → Preview scope
-
Portfolio Docs preview is not deployed
- Ensure portfolio-docs Vercel project has preview deployments enabled
- Create a test PR in portfolio-docs to generate a preview URL
GitHub checks not running
Symptoms:
- PR created but no CI checks appear after 3–5 minutes
- PR shows "Waiting for status to report" indefinitely
Root causes & fixes:
-
CI workflow file syntax error
- Check
.github/workflows/ci.ymlfor YAML formatting - Look for build errors in Actions tab
- Check
-
Wrong trigger event
- Verify workflow triggers on
pull_requestevent:on:
pull_request:
push:
branches: [main]
- Verify workflow triggers on
-
Jobs not named correctly
- Ensure job IDs match what Vercel expects:
qualityandbuild - (They appear as
ci / qualityandci / buildin Vercel)
- Ensure job IDs match what Vercel expects:
-
GitHub Actions not enabled
- Go to repo Settings → Actions → General
- Ensure "Allow all actions and reusable workflows" is selected
CI workflow fails with missing environment variables
Symptoms:
- CI workflow fails on staging or main branch
- Error message:
Environment validation failed: Missing required variables - Specifically missing:
NEXT_PUBLIC_GITHUB_URL,NEXT_PUBLIC_DOCS_GITHUB_URL
Root cause:
These variables must be defined in GitHub repository settings so the CI workflow can access them during builds.
Fix:
Part 1: Add variables to GitHub repository
- Go to your portfolio-app GitHub repository
- Click Settings (top menu)
- In left sidebar, click "Secrets and variables" → "Actions"
- Click "New repository variable" button (blue button, top right)
- Add the following variables (one at a time):
| Name | Value | Example |
|---|---|---|
NEXT_PUBLIC_GITHUB_URL | Your GitHub profile URL | https://github.com/bryce-seefieldt |
NEXT_PUBLIC_DOCS_GITHUB_URL | Your docs repo GitHub URL | https://github.com/bryce-seefieldt/portfolio-docs |
For each variable:
- Click "New repository variable"
- Enter Name (exactly as shown above)
- Enter Value (your GitHub URLs)
- Click "Add variable"
Part 2: Verify variables in Vercel (optional but recommended)
If running workflows that deploy to Vercel, also add these to Vercel environment variables:
- Go to Vercel dashboard → portfolio-app project
- Navigate to Settings → Environment Variables
- For each variable, click "Add New":
- Name:
NEXT_PUBLIC_GITHUB_URLorNEXT_PUBLIC_DOCS_GITHUB_URL - Value: (same as GitHub)
- Environment scope: All Environments (or Preview + Production separately if preferred)
- Name:
- Click "Save"
Part 3: Verify .env.local for local development
Ensure your local .env.local file has these variables:
NEXT_PUBLIC_GITHUB_URL=https://github.com/bryce-seefieldt
NEXT_PUBLIC_DOCS_GITHUB_URL=https://github.com/bryce-seefieldt/portfolio-docs
Part 4: Retry the workflow
- Go to GitHub → Actions
- Click on the failed workflow run
- Click "Re-run jobs" button (top right)
- Monitor the logs for successful environment validation
Expected result: CI workflow should now pass the environment validation gate and proceed to build/smoke tests.
Success Criteria
✅ After completing all phases:
- Vercel project created and connected to GitHub
- Environment variables configured for preview and production
- GitHub Deployment Checks imported and active
- GitHub Ruleset created to protect
mainbranch - Test PR validated:
- Preview deployment created
- CI checks run and pass
- Merge succeeds
- Production promotion automatic after checks
- Production domain verified
- Documentation updated with URLs and configuration
- Team notified of live status
Related artifacts
- ADR-0007: Portfolio App Hosting on Vercel
- Portfolio App Deployment Dossier
- Portfolio App Config Reference
- Portfolio App Environment Contract (
/docs/_meta/env/portfolio-app-env-contract.md) - CI Triage Runbook