From fc3980e7b0a8dec115b31d3d8fe3a0ed240862eb Mon Sep 17 00:00:00 2001 From: Fluory Date: Mon, 28 Sep 2026 10:14:19 +0200 Subject: [PATCH 1/3] ci: let the verify-full label force the full run, also for doc-only PRs AGENTS.md requires verify:full before a release, and the label is the way to ask for it - but the change detection marked a Markdown-only PR as code=false, which skipped install, verify and verify:full. The release PR #86 (CHANGELOG, AGENTS.md, a skill file) thus got no full run. The label now counts as a code change, and adding it to an open PR starts a run (labeled event). PRs without the label are unchanged. Fixes #89 Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/ci.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fc2189..e10e127 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,10 +10,11 @@ name: CI # No branches filter: stacked PRs on slice branches must be checked too. # Explicit types: the defaults (opened, synchronize, reopened) never re-run the PR guard when a draft is -# marked ready (verify-green rule) or when the description is edited. +# marked ready (verify-green rule) or when the description is edited; `labeled` starts the full run when +# `verify-full` is added to an open PR (#89). on: pull_request: - types: [opened, synchronize, reopened, ready_for_review, edited] + types: [opened, synchronize, reopened, ready_for_review, edited, labeled] concurrency: group: ci-${{ github.ref }} @@ -34,7 +35,10 @@ jobs: - name: Detect doc-only changes id: diff run: | - if git diff --name-only "origin/${{ github.base_ref }}...HEAD" | grep -qvE '^docs/|\.md$'; then + # The label `verify-full` counts as a code change (#89): a release PR changes only Markdown + # but must still run verify:full (AGENTS.md). + forced="${{ contains(github.event.pull_request.labels.*.name, 'verify-full') }}" + if [ "$forced" = "true" ] || git diff --name-only "origin/${{ github.base_ref }}...HEAD" | grep -qvE '^docs/|\.md$'; then echo "code=true" >> "$GITHUB_OUTPUT" else echo "code=false" >> "$GITHUB_OUTPUT" From c9b08639ee671ddda614ff3fd7475da9280dbf0e Mon Sep 17 00:00:00 2001 From: Fluory Date: Mon, 28 Sep 2026 10:28:41 +0200 Subject: [PATCH 2/3] ci: install uv before verify:full and let the label force the AI checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fresh review of #90 found that verify:full ends with the eval gate (`uv run …`) while uv was only installed later and only for AI changes: run 36396210580 failed with "uv: not found" - the verify-full label had never worked for a PR without AI changes. uv now comes before verify:full whenever it runs, and the label also forces the AI service checks (ruff, pyright, pytest, eval gate), which belong to verify (AGENTS.md). Refs #89 Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/ci.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e10e127..a09c0f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: else echo "code=false" >> "$GITHUB_OUTPUT" fi - if git diff --name-only "origin/${{ github.base_ref }}...HEAD" | grep -qE '^(services/ai|contracts)/'; then + if [ "$forced" = "true" ] || git diff --name-only "origin/${{ github.base_ref }}...HEAD" | grep -qE '^(services/ai|contracts)/'; then echo "ai=true" >> "$GITHUB_OUTPUT" else echo "ai=false" >> "$GITHUB_OUTPUT" @@ -105,6 +105,11 @@ jobs: id: profile if: steps.diff.outputs.code == 'true' && hashFiles('package.json') != '' run: echo "stage=$(sed -n 's/^[[:space:]]*stage:[[:space:]]*\([a-z]*\).*/\1/p' project-profile.yml | head -1)" >> "$GITHUB_OUTPUT" + # verify:full ends with the eval gate (`uv run …`): uv must exist before it, also without AI changes (#90 review). + - uses: astral-sh/setup-uv@v10.2.0 # no floating v10 tag exists (verified 2026-09-22) + if: hashFiles('services/ai/pyproject.toml') != '' && (steps.diff.outputs.ai == 'true' || (steps.diff.outputs.code == 'true' && hashFiles('package.json') != '' && (steps.profile.outputs.stage == 'production' || contains(github.event.pull_request.labels.*.name, 'verify-full')))) + with: + enable-cache: true - name: Install Playwright Chromium (E2E smoke) if: steps.diff.outputs.code == 'true' && hashFiles('package.json') != '' && (steps.profile.outputs.stage == 'production' || contains(github.event.pull_request.labels.*.name, 'verify-full')) run: pnpm exec playwright install --with-deps chromium @@ -117,10 +122,7 @@ jobs: - name: Foundation phase (AI service) if: steps.diff.outputs.ai == 'true' && hashFiles('services/ai/pyproject.toml') == '' run: echo "No services/ai/pyproject.toml – AI service not created yet." - - uses: astral-sh/setup-uv@v10.2.0 # no floating v10 tag exists (verified 2026-09-22) - if: steps.diff.outputs.ai == 'true' && hashFiles('services/ai/pyproject.toml') != '' - with: - enable-cache: true + # uv is installed above (before verify:full) whenever this section runs. - name: AI service verify (ruff, pyright, pytest) if: steps.diff.outputs.ai == 'true' && hashFiles('services/ai/pyproject.toml') != '' working-directory: services/ai From 88e0788270e25290dfac6cb871567ca01c8c0163 Mon Sep 17 00:00:00 2001 From: Fluory Date: Mon, 28 Sep 2026 11:47:44 +0200 Subject: [PATCH 3/3] build(evals): call uv with --directory only, independent of the uv version In CI (uv 0.12.19, installed as "latest") `uv run --project services/ai --directory services/ai` resolved the project relative to the directory, i.e. services/ai/services/ai, and failed with "Project directory does not exist"; locally uv 0.11.24 resolved it against the start directory. With --directory alone the project is found in services/ai under both. Refs #89 Co-Authored-By: Claude Opus 5.5 (1M context) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad0f015..b1d7006 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "samples:record": "tsx src/samples-record.ts", "contract:types": "openapi-typescript contracts/ai-service.openapi.yaml -o src/features/extraction/ai-service.contract.ts && openapi-typescript contracts/erp-export.openapi.yaml -o src/features/export/erp-export.contract.ts", "e2e": "playwright test", - "evals": "uv run --project services/ai --directory services/ai python -m requestflow_ai.evals --replay" + "evals": "uv run --directory services/ai python -m requestflow_ai.evals --replay" }, "dependencies": { "@aws-sdk/client-s3": "3.1138.0",