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
83 changes: 78 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ jobs:
- name: CI scope self-test
run: npm run check:ci-scope

- name: Pinned Gitleaks range self-test
run: npm run check:gitleaks-pinned

- name: CI triage self-test
run: npm run check:ci-triage

Expand Down Expand Up @@ -330,9 +333,16 @@ jobs:
if: needs.changes.outputs.codex_autofix_changed == 'true'
run: npm run check:codex-autofix-workflow

# Fixtures for ordinary non-docs PRs; full offline contracts (includes
# fixtures) when retrieval/answer surfaces change.
- name: Offline RAG fixture and manifest validation
if: needs.changes.outputs.rag_eval_changed != 'true'
run: npm run check:rag:fixtures

- name: Offline RAG production contracts
if: needs.changes.outputs.rag_eval_changed == 'true'
run: npm run eval:rag:offline

coverage:
name: Unit coverage
needs: changes
Expand Down Expand Up @@ -406,10 +416,53 @@ jobs:
contents: read
uses: ./.github/workflows/docker-image.yml

# Fail-fast @critical Chromium smoke on PRs/merge_group before the full
# production suite. Skipped on main/schedule — those run the full job only.
# Keeps merge safety: pr-required still demands the full Production UI job.
ui-critical-fast:
name: Production UI critical
needs: changes
if: >
needs.changes.outputs.ui_changed == 'true' &&
(github.event_name == 'pull_request' || github.event_name == 'merge_group')
runs-on: ubuntu-24.04
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Setup UI e2e environment
uses: ./.github/actions/setup-ui-e2e

- name: Chromium @critical journeys
run: npm run test:e2e:critical

- name: Classify exact failed test identities
if: failure()
run: node scripts/classify-playwright-failures.mjs

- name: Upload critical UI diagnostics
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: production-ui-critical-diagnostics-${{ github.run_id }}
path: |
test-results/
playwright-report/
if-no-files-found: ignore

ui-critical:
name: Production UI
needs: changes
if: needs.changes.outputs.ui_changed == 'true'
needs: [changes, ui-critical-fast]
# Run when UI scope applies and the fail-fast job succeeded or was skipped
# (skipped on main/schedule/dispatch where critical-first is not used).
if: >
always() &&
needs.changes.result == 'success' &&
needs.changes.outputs.ui_changed == 'true' &&
(needs.ui-critical-fast.result == 'success' || needs.ui-critical-fast.result == 'skipped')
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
Expand Down Expand Up @@ -542,7 +595,11 @@ jobs:

pr-required:
name: PR required
needs: [changes, static-pr, safety, coverage, build, container-images, ui-critical, db-reset-verify]
needs:
[changes, static-pr, safety, coverage, build, container-images, ui-critical-fast, ui-critical, db-reset-verify]
# #095: keep `if: always()` — a skipped required check counts as PASSING
# on GitHub, so `!cancelled()` would cancel-to-green a hand-cancelled tip.
# Cancelled vs failure is distinguished in the script below (PR #1409).
if: always()
runs-on: ubuntu-24.04
timeout-minutes: 5
Expand All @@ -562,6 +619,7 @@ jobs:
COVERAGE_RESULT: ${{ needs.coverage.result }}
BUILD_RESULT: ${{ needs.build.result }}
CONTAINER_RESULT: ${{ needs.container-images.result }}
UI_FAST_RESULT: ${{ needs.ui-critical-fast.result }}
UI_RESULT: ${{ needs.ui-critical.result }}
DB_RESULT: ${{ needs.db-reset-verify.result }}
run: |
Expand Down Expand Up @@ -650,8 +708,14 @@ jobs:
fi

if [ "$UI_CHANGED" = "true" ]; then
if [ "$EVENT_NAME" = "pull_request" ] || [ "$EVENT_NAME" = "merge_group" ]; then
require_success "production-ui-critical" "$UI_FAST_RESULT"
else
require_skipped_or_success "production-ui-critical" "$UI_FAST_RESULT"
fi
require_success "production-ui" "$UI_RESULT"
else
require_skipped_or_success "production-ui-critical" "$UI_FAST_RESULT"
require_skipped_or_success "production-ui" "$UI_RESULT"
fi

Expand Down Expand Up @@ -689,9 +753,18 @@ jobs:

echo "Required in-scope PR checks passed."

# Firefox/WebKit matrix must not wait on pr-required: a blocking weekly
# dependency audit (full-run sentinel sets lockfile_changed) previously
# skipped the matrix entirely while Chromium UI was already green (#023).
release-browser-matrix:
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')
needs: [pr-required]
if: >
always() &&
(github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) &&
needs.changes.result == 'success' &&
needs.static-pr.result == 'success' &&
(needs.build.result == 'success' || needs.build.result == 'skipped') &&
(needs.ui-critical.result == 'success' || needs.ui-critical.result == 'skipped')
needs: [changes, static-pr, build, ui-critical]
runs-on: ubuntu-24.04
timeout-minutes: 70

Expand Down
40 changes: 34 additions & 6 deletions .github/workflows/secret-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,50 @@ permissions:
pull-requests: read
security-events: write

env:
# Match the version gitleaks-action@v3 installs by default.
GITLEAKS_VERSION: "8.24.3"
# SHA-256 of gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz from the release
# checksums.txt (https://github.com/gitleaks/gitleaks/releases/tag/v8.24.3).
GITLEAKS_LINUX_X64_SHA256: "9991e0b2903da4c8f6122b5c3186448b927a5da4deef1fe45271c3793f4ee29c"

jobs:
gitleaks:
name: Gitleaks
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Checkout
- name: Checkout pinned head
# gitleaks/gitleaks-action@v3 does not support the merge_group event;
# the scan already ran on pull_request so skipping here is safe.
if: github.event_name != 'merge_group'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
# Pin the workspace to the triggering SHA so a later push cannot move
# HEAD under the scanner (#097).
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false

- name: Scan for secrets
# gitleaks/gitleaks-action@v3 does not support the merge_group event;
# the scan already ran on pull_request so skipping here is safe.
- name: Install Gitleaks
if: github.event_name != 'merge_group'
run: |
set -euo pipefail
archive="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
curl -fsSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${archive}" -o /tmp/gitleaks.tgz
echo "${GITLEAKS_LINUX_X64_SHA256} /tmp/gitleaks.tgz" | sha256sum -c -
tar -xzf /tmp/gitleaks.tgz -C /tmp gitleaks
sudo install -m 0755 /tmp/gitleaks /usr/local/bin/gitleaks
gitleaks version

- name: Scan for secrets (pinned event SHAs)
# Do not use gitleaks-action's PR path: it re-queries the commits API and
# can build a range against a newer tip that is absent from this checkout
# (#097). Event payload SHAs are immutable for the run.
if: github.event_name != 'merge_group'
uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_BIN: gitleaks
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITLEAKS_PINNED_BASE: ${{ github.event.pull_request.base.sha || github.event.before }}
GITLEAKS_PINNED_HEAD: ${{ github.event.pull_request.head.sha || github.sha }}
run: node scripts/run-gitleaks-pinned.mjs
4 changes: 4 additions & 0 deletions docs/branch-review-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,7 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie
| 2026-07-30 | PR #1396 / claude/latency-findings-impl-s8g01v | 70e810b66881e17aa9f58126fdad970986bda911 | User ask: resolve comments + Production UI phone-scroll + main sync | FIXED: synced main (DIRTY was staleness); removed union ledger dup; adapted phone-scroll asserts for Answer strategy-overlay + overlay/reserve-only calculator budget + focus pre-scroll inside 8px reveal band. Codex P1s already on tip; 0 unresolved threads. Focused Chromium phone-scroll 9/9 green (system Chrome). | phone-scroll focused 9/9; check:branch-review-ledger PASS; merge-tree clean; prior Codex P1s retained |
| 2026-07-30 | HEAD | 13c16cf07c854b50daa35a2ef2a2ea76d5e059e1 | ci-testing-approach | findings: UI-load flake #093 dominates PR reds; schedule full-sentinel blocks release-browser via audit; UI scope overfires on src/app/api; ~40% PR runs cancelled wasting ~12 UI-hrs; CI_TRIAGE inert; eval:rag:offline claimed-in-CI but only fixtures run | gh-ci-500-runs,ci.yml,ci-change-scope,testing.md,process-hardening,outstanding-issues-093-095-097-023,flake-ledger-empty |
| 2026-07-30 | cursor/ci-testing-review-1bf5 | 13c16cf07c854b50daa35a2ef2a2ea76d5e059e1 | ci-testing-approach | Corrects the ref cell from the unresolved placeholder "HEAD" to the actual branch name, so ledger:lookup can match this review by branch (Codex P2 finding on PR #1406). | node scripts/branch-review-ledger.mjs lookup cursor/ci-testing-review-1bf5 --scope ci-testing-approach |
| 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | ad9da6a6f8ba3884b389fa78e678bb88ee72d9d1 | ci-hygiene-gates | implemented matrix unblock, scope narrow, cancelled≠failure, pinned gitleaks, critical-first UI, eval:rag:offline; skipped #093; verify:cheap 4471 pass | verify:cheap,check:ci-scope,check:gitleaks-pinned,check:gate-manifest,eval:rag:offline |
| 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | b660dbc5a10d7ca3da03541028017f0abc6b5bd3 | ci-hygiene-gates merge-readiness | findings | check:ci-scope;check:gitleaks-pinned;scope-classify PR files ui_changed=false;sim cancelled-as-neutral |
| 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | 8f3283d00da274dee507a1b8e9b611321d1f35be | pr-1413-merge-readiness | READY after main sync + cancel-to-green fix; draft until tip CI green; deferred #093 + CI_TRIAGE_ENABLED confirm | verify:cheap:4481-pass;format:outstanding-issues;merge-tree:clean;cancelled:!cancelled();hosted:awaiting-tip |
| 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | 0d70de480f370fec3e7f3774f13d906318a09b3c | pr-1413-merge-readiness | READY: synced with main/#1409; tip CI success incl PR required; draft; deferred #093 + CI_TRIAGE_ENABLED | merge-tree:clean;ci-cache-safety:13/13;hosted:30520195863:success;PR-required:pass |
Loading
Loading