fix(awards): audit findings — multi-pick, empty ballots, stale prefil… #2597
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Contract gate | |
| # PR-time contract-as-code enforcement (the 2026-07-08 schema-drift lesson): | |
| # 1. specs/openapi.json (committed snapshot) must match the spec the route | |
| # serves — a spec edit without the regenerated snapshot fails. | |
| # 2. api-client/src/schema.ts is GENERATED from the snapshot — mirror-drift | |
| # is impossible; stale types fail. | |
| # 3. A snapshot change without a changelog entry fails — contract changes | |
| # must be announced (downstream drift detectors classify from | |
| # /api/changelog). | |
| # The daily live checks (api-drift.yml field coverage) remain the backstop | |
| # for data/deploy drift PR-time can't see. | |
| # | |
| # The lessons step exits 1 BY DESIGN while any lesson still says `Guard: none` | |
| # — that red is the signal (a lesson that never became a check), not the lane | |
| # breaking (read by scripts/check-workflow-health.ts): | |
| # workflow-health: signal-steps: ^Every lesson names its guard$ | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| jobs: | |
| contract: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| # Full history: the changelog-coupling step diffs against the PR | |
| # base's merge-base, which a shallow clone can't resolve (exit 128). | |
| fetch-depth: 0 | |
| - uses: pnpm/action-setup@v4 | |
| with: { version: 10 } | |
| - uses: actions/setup-node@v4 | |
| with: { node-version: "24", cache: "pnpm" } | |
| - run: pnpm install --frozen-lockfile | |
| - name: Contract artifacts fresh (snapshot + generated client types) | |
| run: pnpm contract:check | |
| - name: Writer conformance (read-back, pipefail, exit-stomps, probe coverage) | |
| run: pnpm exec tsx scripts/check-writer-conformance.ts | |
| # A lesson only counts when it became a check. Every improvements/lessons | |
| # file names its guard (test / guard script / workflow) or says `none`. | |
| # Reported, not blocking, while `none` lines remain — declared as a | |
| # signal step in the header so the red reads as "unguarded lessons", | |
| # never as a broken lane. Flip continue-on-error to false the day every | |
| # lesson is guarded; from then on a new unguarded lesson fails the PR. | |
| - name: Every lesson names its guard | |
| continue-on-error: true | |
| run: pnpm exec tsx scripts/check-lessons-guarded.ts | |
| - name: Routing surface stays terse (sls-051 — descriptions ≤600 chars, no docs-question capture) | |
| run: pnpm exec tsx scripts/eval/routing-surface-check.ts | |
| # Every served value must be datable, or say it is not. Raven #1134: a | |
| # DeepWiki answer sat beside three dates that all described the code scan | |
| # and none dated the answer. Ratcheted at 40 — new ones fail. | |
| - name: Served values are datable | |
| run: pnpm exec tsx scripts/check-answer-dating.ts | |
| - name: Route files export only handlers + config (2026-07-21 — non-handler exports break next build, tsc/vitest miss it) | |
| run: pnpm exec tsx scripts/eval/route-exports-check.ts | |
| - name: Changelog⇄contract assertion (sls-054) | |
| # The newest changelog entry may not name response fields absent from | |
| # the published schema — the changelog is a consumption contract. | |
| run: pnpm exec tsx scripts/eval/changelog-contract-check.ts | |
| - name: Spec change requires a changelog entry | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| git fetch origin "${{ github.base_ref }}" --depth=50 | |
| CHANGED=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD") | |
| if echo "$CHANGED" | grep -qx "specs/openapi.json"; then | |
| if ! echo "$CHANGED" | grep -qx "src/lib/changelog.ts"; then | |
| echo "::error::specs/openapi.json changed without a changelog entry. Contract changes must be announced — add an entry to src/lib/changelog.ts in this PR." | |
| exit 1 | |
| fi | |
| echo "spec changed + changelog updated — OK" | |
| else | |
| echo "no contract change in this PR" | |
| fi |