diff --git a/errors/caching-artifacts/ca-146.yml b/errors/caching-artifacts/ca-146.yml
new file mode 100644
index 0000000..8cea196
--- /dev/null
+++ b/errors/caching-artifacts/ca-146.yml
@@ -0,0 +1,127 @@
+id: ca-146
+title: 'download-artifact v4/v5 Fails with "Request timeout" When Downloading Large Artifacts from Blob Storage'
+category: caching-artifacts
+severity: error
+tags:
+  - download-artifact
+  - artifact
+  - timeout
+  - blob-storage
+  - request-timeout
+  - transient
+  - large-artifact
+patterns:
+  - regex: 'Unable to download and extract artifact: Request timeout:'
+    flags: 'i'
+  - regex: 'Unable to download artifact\(s\): Unable to download and extract artifact: Request timeout'
+    flags: 'i'
+  - regex: 'download and extract artifact.*Request timeout'
+    flags: 'i'
+error_messages:
+  - 'Unable to download artifact(s): Unable to download and extract artifact: Request timeout: /actions-results/...'
+  - 'Error: Unable to download artifact(s): Unable to download and extract artifact: Request timeout'
+  - 'Request timeout: https://productionresultssa.blob.core.windows.net/...'
+root_cause: |
+  `actions/download-artifact@v4+` downloads artifact content from Azure Blob Storage
+  via a time-limited SAS URL. When the artifact download takes too long — due to
+  large artifact size, network congestion between the GitHub Actions runner and Azure
+  Blob Storage, or throttling on the blob storage endpoint — the SAS URL's embedded
+  time window expires while the download is still in progress.
+
+  The error manifests as a `Request timeout:` followed by the full blob storage URL
+  (including the expiring `se=` query parameter). This is distinct from:
+  - `Artifact download failed after N retries` — which covers retry exhaustion
+  - `Not a valid zip file` — which covers corrupt downloads
+
+  The issue is intermittent: retrying the workflow often succeeds because a fresh SAS
+  URL with a new time window is generated. Large artifacts (typically >1 GB uncompressed
+  or >500 MB compressed) are most susceptible. GitHub-hosted runners in certain regions
+  can also experience higher latency to the blob storage endpoint.
+
+  First reported widely in actions/download-artifact#249 (115 reactions). The root
+  cause is that the SAS URL timeout is calculated from the time the artifact download
+  request is initiated, not from the time the runner begins pulling bytes — so if the
+  runner is under load or the storage endpoint is slow to respond, the window can
+  close mid-download.
+fix: |
+  There is no user-side configuration to extend the SAS URL timeout. Options:
+
+  1. **Re-run the failed job**: A fresh workflow run generates a new SAS URL with a
+     new time window. This is the simplest fix for transient occurrences.
+
+  2. **Reduce artifact size**: Split large artifacts into smaller named artifacts using
+     multiple `upload-artifact` steps and download them in parallel or sequentially.
+     Smaller artifacts are less likely to time out.
+
+  3. **Use `actions/cache` instead of artifacts** for build outputs that are only
+     consumed within the same workflow. Cache restores use the same blob backend but
+     have more lenient timeout handling.
+
+  4. **Check for runner resource contention**: Artifacts download over the runner's
+     network. If the runner is simultaneously performing other I/O-heavy operations,
+     the effective download bandwidth may be reduced. Isolate the download step.
+
+  5. **Upgrade to latest action version**: `actions/download-artifact@v5` and later
+     include improved retry logic and timeout handling compared to v4.x releases.
+fix_code:
+  - language: yaml
+    label: 'Split large artifact into smaller named parts to reduce per-download size'
+    code: |
+      jobs:
+        build:
+          runs-on: ubuntu-latest
+          steps:
+            - uses: actions/checkout@v4
+
+            - name: Build frontend
+              run: npm run build
+
+            # Upload as separate smaller artifacts instead of one large one
+            - name: Upload dist/js
+              uses: actions/upload-artifact@v4
+              with:
+                name: dist-js
+                path: dist/js/
+
+            - name: Upload dist/css
+              uses: actions/upload-artifact@v4
+              with:
+                name: dist-css
+                path: dist/css/
+
+        deploy:
+          needs: build
+          runs-on: ubuntu-latest
+          steps:
+            # Download smaller artifacts separately — each less likely to timeout
+            - uses: actions/download-artifact@v4
+              with:
+                name: dist-js
+                path: dist/js/
+
+            - uses: actions/download-artifact@v4
+              with:
+                name: dist-css
+                path: dist/css/
+  - language: yaml
+    label: 'Upgrade to latest download-artifact version with improved retry/timeout handling'
+    code: |
+      steps:
+        # Prefer latest version — v5+ has better timeout/retry logic than v4.x
+        - uses: actions/download-artifact@v5
+          with:
+            name: my-artifact
+            path: artifacts/
+prevention:
+  - 'Keep individual artifact sizes under 500 MB compressed where possible to reduce timeout exposure'
+  - 'Use actions/cache instead of artifacts for inter-job data that does not need to persist beyond the workflow'
+  - 'Split large build outputs into multiple named artifacts and download them separately'
+  - 'Pin to the latest major version of download-artifact to get improved timeout handling'
+  - 'Add retry logic at the workflow level using continue-on-error and a subsequent re-download step as a fallback'
+docs:
+  - url: 'https://github.com/actions/download-artifact/issues/249'
+    label: 'actions/download-artifact#249: Unable to download and extract artifact: Request timeout (115 reactions)'
+  - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/storing-workflow-data-as-artifacts'
+    label: 'GitHub Docs: Storing workflow data as artifacts'
+  - url: 'https://github.com/actions/download-artifact'
+    label: 'actions/download-artifact — changelog and migration guide'
diff --git a/errors/caching-artifacts/ca-147.yml b/errors/caching-artifacts/ca-147.yml
new file mode 100644
index 0000000..8500aaa
--- /dev/null
+++ b/errors/caching-artifacts/ca-147.yml
@@ -0,0 +1,124 @@
+id: ca-147
+title: '`deploy-pages@v4` Fails with "HttpError: No artifact_url provided" When Using Mismatched upload-pages-artifact Version'
+category: caching-artifacts
+severity: error
+tags:
+  - deploy-pages
+  - upload-pages-artifact
+  - pages
+  - artifact-url
+  - version-mismatch
+  - HttpError
+  - github-pages
+patterns:
+  - regex: 'HttpError: No artifact_url provided'
+    flags: 'i'
+  - regex: 'Creating Pages deployment failed'
+    flags: 'i'
+  - regex: 'Failed to create deployment \(status: 400\).*No artifact_url provided'
+    flags: 'i'
+error_messages:
+  - 'Error: Creating Pages deployment failed'
+  - 'Error: HttpError: No artifact_url provided'
+  - "Error: Error: Failed to create deployment (status: 400) with build version <sha>. Responded with: No artifact_url provided"
+root_cause: |
+  `actions/deploy-pages@v4` introduced a new GitHub Pages deployment API that requires
+  an `artifact_url` field in the deployment payload. This URL is produced by
+  `actions/upload-pages-artifact@v3` (and later) — older versions of the action
+  (`upload-pages-artifact@v1` and `v2`) do not generate this URL and instead use
+  the legacy artifact ID-based flow.
+
+  When a workflow uses `deploy-pages@v4` together with `upload-pages-artifact@v1`
+  or `v2`, the deploy step fails with HTTP 400 because `artifact_url` is absent from
+  the payload that `deploy-pages` assembles from the prior step's outputs.
+
+  The stack trace makes the cause look like an API error (`No artifact_url provided`)
+  rather than a version mismatch in the workflow, which makes it difficult to diagnose.
+
+  Additionally, swapping ONLY `upload-pages-artifact` to `@v3` while keeping older
+  `deploy-pages` (v2 or v3) can also fail, because the upload and deploy actions must
+  be from compatible major version pairs:
+  - `upload-pages-artifact@v3` + `deploy-pages@v4` → compatible
+  - `upload-pages-artifact@v1`/`v2` + `deploy-pages@v4` → fails (No artifact_url)
+  - `upload-pages-artifact@v3` + `deploy-pages@v2`/`v3` → fails (format mismatch)
+
+  Reported in actions/deploy-pages#284 (34 reactions).
+fix: |
+  Always update `upload-pages-artifact` and `deploy-pages` together to matching
+  major versions. The compatible pairs are:
+
+  - `upload-pages-artifact@v1` + `deploy-pages@v2`  (legacy, no longer recommended)
+  - `upload-pages-artifact@v3` + `deploy-pages@v4`  (current, recommended)
+
+  Do not mix major versions between the two actions.
+fix_code:
+  - language: yaml
+    label: 'BROKEN — upload-pages-artifact v1/v2 with deploy-pages v4 causes "No artifact_url"'
+    code: |
+      # BROKEN: mismatched versions
+      jobs:
+        deploy:
+          runs-on: ubuntu-latest
+          permissions:
+            pages: write
+            id-token: write
+          steps:
+            - uses: actions/checkout@v4
+
+            - name: Build site
+              run: npm run build
+
+            # v1 does not produce artifact_url — incompatible with deploy-pages@v4
+            - name: Upload pages artifact
+              uses: actions/upload-pages-artifact@v1
+              with:
+                path: dist/
+
+            - name: Deploy to GitHub Pages
+              uses: actions/deploy-pages@v4   # v4 requires artifact_url from v3+
+  - language: yaml
+    label: 'FIXED — upgrade both actions to their current compatible major versions'
+    code: |
+      # FIXED: matching major versions
+      jobs:
+        build:
+          runs-on: ubuntu-latest
+          steps:
+            - uses: actions/checkout@v4
+
+            - name: Build site
+              run: npm run build
+
+            # v3 produces the artifact_url field required by deploy-pages@v4
+            - name: Upload pages artifact
+              uses: actions/upload-pages-artifact@v3
+              with:
+                path: dist/
+
+        deploy:
+          needs: build
+          runs-on: ubuntu-latest
+          environment:
+            name: github-pages
+            url: ${{ steps.deployment.outputs.page_url }}
+          permissions:
+            pages: write
+            id-token: write
+          steps:
+            - name: Deploy to GitHub Pages
+              id: deployment
+              uses: actions/deploy-pages@v4
+prevention:
+  - 'Always bump upload-pages-artifact and deploy-pages together — they are a matched pair and must use compatible major versions'
+  - 'When updating one, immediately search your workflow for the other and update it in the same PR'
+  - 'Use the official GitHub Pages workflow starter template which keeps both actions in sync'
+  - 'Add a comment in your workflow noting the required version pairing to warn future maintainers'
+docs:
+  - url: 'https://github.com/actions/deploy-pages/issues/284'
+    label: 'actions/deploy-pages#284: Actions fail after update to v4 and upload-pages-artifact v3 (34 reactions)'
+  - url: 'https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site'
+    label: 'GitHub Docs: Configuring a publishing source for GitHub Pages'
+  - url: 'https://github.com/actions/deploy-pages/releases'
+    label: 'actions/deploy-pages — releases and migration notes'
+  - url: 'https://github.com/actions/upload-pages-artifact/releases'
+    label: 'actions/upload-pages-artifact — releases and migration notes'
diff --git a/errors/runner-environment/re-489.yml b/errors/runner-environment/re-489.yml
new file mode 100644
index 0000000..ade1988
--- /dev/null
+++ b/errors/runner-environment/re-489.yml
@@ -0,0 +1,130 @@
+id: re-489
+title: '`actions/checkout` Fails with "couldn''t find remote ref refs/pull/N/merge" for PRs with Merge Conflicts'
+category: runner-environment
+severity: error
+tags:
+  - checkout
+  - pull-request
+  - merge-ref
+  - merge-conflict
+  - refs-pull-merge
+  - git
+  - draft-pr
+patterns:
+  - regex: "fatal: couldn't find remote ref refs/pull/\\d+/merge"
+    flags: 'i'
+  - regex: 'refs/pull/\d+/merge.*not found|couldn.t find.*refs/pull/\d+/merge'
+    flags: 'i'
+  - regex: "Error: fatal: couldn't find remote ref refs/pull"
+    flags: 'i'
+error_messages:
+  - "fatal: couldn't find remote ref refs/pull/123/merge"
+  - "Error: fatal: couldn't find remote ref refs/pull/123/merge"
+  - "fatal: repository 'https://github.com/...' not found"
+root_cause: |
+  GitHub creates a virtual `refs/pull/{N}/merge` reference for each open pull request
+  to represent the result of merging the PR's head commit into the base branch. This
+  ref is useful for CI workflows that want to test the merged code (not just the PR
+  head) — it is commonly referenced as:
+
+  ```yaml
+  uses: actions/checkout@v4
+  with:
+    ref: refs/pull/${{ github.event.pull_request.number }}/merge
+  ```
+
+  However, GitHub only generates this virtual ref when the PR can be **cleanly merged**
+  into the base branch with no conflicts. In the following cases the ref does NOT exist:
+
+  - The PR has **merge conflicts** with the base branch
+  - The PR is a **draft** and GitHub hasn't computed the merge result yet
+  - The PR was just opened and the merge ref hasn't been computed yet (brief race)
+  - The base branch was force-pushed after the merge ref was last computed
+
+  When `refs/pull/N/merge` doesn't exist, `actions/checkout` calls `git fetch` for
+  that ref and git returns `fatal: couldn't find remote ref refs/pull/123/merge`,
+  causing the step — and by default the entire workflow — to fail.
+
+  This is especially frustrating because the same workflow succeeds on clean PRs and
+  silently starts failing once a conflict is introduced, making the CI appear broken
+  for reasons unrelated to the code change.
+fix: |
+  Option 1 (recommended): Check out the PR's HEAD ref (`refs/pull/N/head`) instead
+  of the merge ref. This always exists but tests the PR's code without the merge
+  applied. For most CI purposes this is sufficient.
+
+  Option 2: Add a guard step that checks if the merge ref is reachable before
+  attempting to check it out, and fail with a clear message ("PR has merge conflicts,
+  please resolve before CI can test the merged result") instead of a cryptic git error.
+
+  Option 3: Use `actions/checkout` default behavior (checkout the triggering SHA)
+  and skip the manual `ref:` override. The default checkout in a pull_request workflow
+  uses the merge commit if available, or the head commit if the merge ref is absent.
+
+  Option 4 (for workflow_run or cross-event contexts): access the merge SHA via
+  `github.event.pull_request.merge_commit_sha` and check it is non-null before use.
+fix_code:
+  - language: yaml
+    label: 'BROKEN — refs/pull/N/merge fails when PR has conflicts or merge ref not yet computed'
+    code: |
+      # BROKEN: fails silently when PR has merge conflicts
+      jobs:
+        test:
+          runs-on: ubuntu-latest
+          steps:
+            - uses: actions/checkout@v4
+              with:
+                # This ref does not exist for conflicting PRs
+                ref: refs/pull/${{ github.event.pull_request.number }}/merge
+  - language: yaml
+    label: 'OPTION 1 — use refs/pull/N/head (always exists, no merge applied)'
+    code: |
+      jobs:
+        test:
+          runs-on: ubuntu-latest
+          steps:
+            - uses: actions/checkout@v4
+              with:
+                # Always exists — checks out the PR's HEAD commit
+                ref: refs/pull/${{ github.event.pull_request.number }}/head
+  - language: yaml
+    label: 'OPTION 2 — guard: skip merge-ref checkout and fail with a clear message when mergeable is null/false'
+    code: |
+      jobs:
+        test:
+          runs-on: ubuntu-latest
+          steps:
+            - name: Check if PR is mergeable
+              env:
+                MERGEABLE: ${{ github.event.pull_request.mergeable }}
+              run: |
+                if [ "$MERGEABLE" = "false" ] || [ -z "$MERGEABLE" ]; then
+                  echo "::error::PR has merge conflicts or mergeability not yet computed. Resolve conflicts before CI can test the merged result."
+                  exit 1
+                fi
+
+            - uses: actions/checkout@v4
+              with:
+                ref: refs/pull/${{ github.event.pull_request.number }}/merge
+  - language: yaml
+    label: 'OPTION 3 — rely on default checkout behavior (uses merge commit when available)'
+    code: |
+      jobs:
+        test:
+          runs-on: ubuntu-latest
+          steps:
+            # Default checkout in pull_request context uses merge commit if mergeable,
+            # otherwise falls back to the head commit — no manual ref needed
+            - uses: actions/checkout@v4
+prevention:
+  - 'Avoid hardcoding refs/pull/N/merge in workflows — use the default checkout or refs/pull/N/head instead'
+  - 'If you must test the merged result, guard with a mergeability check step first and emit a clear error for conflicting PRs'
+  - 'Add a required status check that validates PR mergeability so contributors resolve conflicts before CI runs the merge-dependent step'
+  - 'Note that github.event.pull_request.mergeable can be null (not yet computed) on very recently opened PRs — treat null as non-mergeable'
+docs:
+  - url: 'https://docs.github.com/en/rest/pulls/pulls#get-a-pull-request'
+    label: 'GitHub REST API: Get a pull request — mergeable and merge_commit_sha fields'
+  - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/events-that-trigger-workflows#pull_request'
+    label: 'GitHub Docs: pull_request event — checkout behavior'
+  - url: 'https://github.com/actions/checkout'
+    label: 'actions/checkout — default ref behavior documentation'
