|
| 1 | +# CLAUDE.md |
| 2 | +<!-- Generated by APM CLI --> |
| 3 | +<!-- Build ID: a4fd78d3a4a3 --> |
| 4 | +<!-- APM Version: 0.14.1 --> |
| 5 | + |
| 6 | +# Project Standards |
| 7 | + |
| 8 | +## Files matching `.github/workflows/**` |
| 9 | + |
| 10 | +<!-- Source: local .apm/instructions/cicd.instructions.md --> |
| 11 | +# CI/CD Pipeline Instructions |
| 12 | + |
| 13 | +## Workflow Architecture (Tiered + Merge Queue) |
| 14 | +Five workflows split by trigger and tier. PRs get fast feedback; the heavy |
| 15 | +integration suite runs only at merge time via GitHub Merge Queue |
| 16 | +(microsoft/apm#770). |
| 17 | + |
| 18 | +1. **`ci.yml`** - Tier 1, runs on `pull_request` AND `merge_group` |
| 19 | + - **Linux-only** (ubuntu-24.04). Combined `build-and-test` job: unit tests + binary build in a single runner. No secrets needed. |
| 20 | + - Uploads Linux x86_64 binary artifact for downstream integration testing. |
| 21 | + - Runs in both PR context (fast feedback for contributors) and merge_group |
| 22 | + context (against the tentative merge commit before queue auto-merges). |
| 23 | +2. **`ci-integration.yml`** - Tier 2, `merge_group` trigger only |
| 24 | + - **Linux-only**. Builds binary inline, then runs smoke + integration + |
| 25 | + release-validation against the tentative merge commit. |
| 26 | + - Trust boundary is the write-access grant (only users with write can |
| 27 | + enqueue a PR). No environment approval gate. |
| 28 | + - Inlines the binary build instead of fetching from `ci.yml` to avoid |
| 29 | + cross-workflow artifact plumbing across triggers. |
| 30 | + - **Never add a `pull_request` or `pull_request_target` trigger here.** |
| 31 | + This file holds production secrets (`GH_CLI_PAT`, `ADO_APM_PAT`). |
| 32 | + Required-check satisfaction at PR time is handled by `merge-gate.yml`, |
| 33 | + which aggregates all required signals into a single `gate` check. |
| 34 | +3. **`merge-gate.yml`** - single-authority PR-time aggregator |
| 35 | + - Triggers on `pull_request` only (single trigger - dual-trigger with |
| 36 | + `pull_request_target` produces SUCCESS+CANCELLED check-run twins via |
| 37 | + `cancel-in-progress` and poisons branch protection's rollup). |
| 38 | + - One job named `gate`. Polls the Checks API for all entries in the |
| 39 | + workflow's `EXPECTED_CHECKS` env var; aggregates pass/fail into a |
| 40 | + single check-run. |
| 41 | + - Branch protection requires ONLY this one check (`gate`). Adding, |
| 42 | + renaming, or removing an underlying check is a `merge-gate.yml` edit, |
| 43 | + never a ruleset edit. Tide / bors single-authority pattern. |
| 44 | + - Recovery if the `pull_request` webhook is dropped: empty commit, |
| 45 | + `gh workflow run merge-gate.yml -f pr_number=NNN`, or close+reopen. |
| 46 | + - `.github/CODEOWNERS` requires Lead Maintainer review for any change |
| 47 | + to `.github/workflows/**`. |
| 48 | +4. **`build-release.yml`** - `push` to main, tags, schedule, `workflow_dispatch` |
| 49 | + - **Linux + Windows** run combined `build-and-test` (unit tests + binary build in one job). Unit tests run on every push for platform-regression signal; **smoke tests are gated to tag/schedule/dispatch only** (promotion boundaries) to avoid duplicating `ci-integration.yml`'s merge-time smoke and to cut redundant codex-binary downloads. |
| 50 | + - **macOS Intel** uses `build-and-validate-macos-intel` (root node, runs own unit tests - no dependency on `build-and-test`). Builds the binary on every push for early regression feedback; integration + release-validation phases conditional on tag/schedule/dispatch. |
| 51 | + - **macOS ARM** uses `build-and-validate-macos-arm` (root node, tag/schedule/dispatch only - ARM runners are extremely scarce with 2-4h+ queue waits). Only requested when the binary is actually needed for a release. |
| 52 | + - Secrets always available. Full 5-platform binary output (linux x86_64/arm64, darwin x86_64/arm64, windows x86_64). |
| 53 | +5. **`ci-runtime.yml`** - nightly schedule, manual dispatch, path-filtered push |
| 54 | + - **Linux x86_64 only**. Live inference smoke tests (`apm run`) isolated from release pipeline. |
| 55 | + - Uses `GH_MODELS_PAT` for GitHub Models API access. |
| 56 | + - Failures do not block releases - annotated as warnings. |
| 57 | + |
| 58 | +## Platform Testing Strategy |
| 59 | +- **PR time**: Linux-only combined build-and-test in `ci.yml`. Catches logic bugs and dependency issues before merge. Windows + macOS are tested post-merge (platform-specific issues are rare and the full matrix runs on every push to main). |
| 60 | +- **Post-merge**: Full 5-platform matrix (linux x86_64/arm64, darwin x86_64/arm64, windows x86_64) catches remaining platform-specific issues on main. |
| 61 | +- **Rationale**: ci.yml has always been Linux-only - Windows and macOS are covered by `build-release.yml` on every push to main. This keeps PR feedback fast while still catching platform issues before release. |
| 62 | + |
| 63 | +## PyInstaller Binary Packaging |
| 64 | +- **CRITICAL**: Uses `--onedir` mode (NOT `--onefile`) for faster CLI startup performance |
| 65 | +- **Binary Structure**: Creates `dist/{binary_name}/apm` (nested directory containing executable + dependencies) |
| 66 | +- **Platform Naming**: `apm-{platform}-{arch}` (e.g., `apm-darwin-arm64`, `apm-linux-x86_64`) |
| 67 | +- **Spec File**: `build/apm.spec` handles data bundling, hidden imports, and UPX compression |
| 68 | + |
| 69 | +## Artifact Flow Quirks |
| 70 | +- **Upload**: Artifacts include both binary directory + test scripts for isolation testing |
| 71 | +- **Download**: GitHub Actions creates nested structure: `{artifact_name}/dist/{binary_name}/apm` |
| 72 | +- **Release Prep**: Extract binary from nested path using `tar -czf "${binary}.tar.gz" -C "${artifact_dir}/dist" "${binary}"` |
| 73 | + |
| 74 | +## Critical Testing Phases |
| 75 | +1. **Integration Tests**: Full source code access for comprehensive testing |
| 76 | +2. **Release Validation**: ISOLATION testing - no source checkout, validates exact shipped binary experience |
| 77 | +3. **Path Resolution**: Use symlinks and PATH manipulation for isolated binary testing |
| 78 | + |
| 79 | +## Inference Testing (Decoupled) |
| 80 | +- Live inference tests (`apm run`) are **isolated** in `ci-runtime.yml` - they do NOT gate releases |
| 81 | +- `APM_RUN_INFERENCE_TESTS=1` env var enables inference in test scripts; absent = skipped |
| 82 | +- `GH_MODELS_PAT` is only used in `ci-runtime.yml` and Tier 2 smoke-test job - NOT in integration-tests or release-validation |
| 83 | +- Rationale: 8 inference executions x 2% failure rate = 14.9% false-negative per release; APM core UVPs require zero live inference |
| 84 | + |
| 85 | +## Release Flow Dependencies |
| 86 | +- **PR workflow**: Tier 1 only - ci.yml (build-and-test, Linux-only) provides fast feedback. Tier 2 does not run until enqueued. |
| 87 | +- **Merge queue workflow**: ci.yml (Tier 1 against tentative merge ref) + ci-integration.yml (Tier 2: build -> smoke-test -> integration-tests -> release-validation). Queue auto-merges on success; ejects on failure. |
| 88 | +- **Push/Release workflow (Linux + Windows)**: build-and-test -> integration-tests -> release-validation -> create-release -> publish-pypi -> update-homebrew (gh-aw-compat runs in parallel, informational) |
| 89 | +- **Push/Release workflow (macOS Intel)**: build-and-validate-macos-intel (root node: unit tests + build always + conditional integration/release-validation) -> create-release |
| 90 | +- **Push/Release workflow (macOS ARM)**: build-and-validate-macos-arm (root node, tag/schedule/dispatch only; all phases run) -> create-release |
| 91 | +- **Tag Triggers**: Only `v*.*.*` tags trigger full release pipeline |
| 92 | +- **Artifact Retention**: 30 days for debugging failed releases |
| 93 | +- **Cross-workflow artifacts**: ci-integration.yml builds the binary inline (no cross-workflow artifact transfer); build-release.yml jobs share artifacts within the same workflow run. |
| 94 | + |
| 95 | +## Branch Protection & Required Checks |
| 96 | +- **Single required check**: branch protection (`main-protection` ruleset id 9294522) requires exactly one status check context: `gate` from `merge-gate.yml`. All other PR-time signals are aggregated by that workflow's poll loop. |
| 97 | +- **CRITICAL ruleset gotcha**: the ruleset `context` must be the literal check-run name `gate`. `Merge Gate / gate` is only how GitHub may render the workflow and job together in the UI; it is not the context value to store in the ruleset. If the ruleset stores `Merge Gate / gate`, GitHub waits forever with "Expected - Waiting for status to be reported" because no check-run with that literal name is posted. |
| 98 | +- **How the name is derived**: GitHub matches the check by `integration_id` (`15368` = github-actions) plus the emitted check-run name. That emitted name comes from the job `name:` if one is set; otherwise it falls back to the job id. In `merge-gate.yml` the job id is `gate` and `name: gate`, so the emitted check-run name is `gate` -- that is the exact string the ruleset must require. |
| 99 | +- **Adding a new aggregated check**: add it to `EXPECTED_CHECKS` in `merge-gate.yml`. Do not change the ruleset unless you intentionally rename the merge gate job's emitted check-run name, in which case the ruleset `context` must be updated to the new exact name. |
| 100 | + |
| 101 | +## Trust Model |
| 102 | +- **PR push (any contributor, including forks)**: Runs Tier 1 only. No CI secrets exposed. PR code is checked out and tested in an unprivileged context. |
| 103 | +- **merge_group (write access required)**: Runs Tier 1 + Tier 2. Tier 2 sees secrets. The `gh-readonly-queue/main/*` ref is created by GitHub from the PR merged into main; only users with write access can trigger this by enqueueing a PR. |
| 104 | +- **Trust boundary = write-access grant**, managed in repo Settings -> Collaborators. Write access is granted only to vetted contributors. |
| 105 | +- **No environment approval gate** is required because the act of enqueueing IS the trust assertion. This replaces the previous `integration-tests` environment approval flow. |
| 106 | + |
| 107 | +## Key Environment Variables |
| 108 | +- `PYTHON_VERSION: '3.12'` - Standardized across all jobs |
| 109 | +- `GITHUB_TOKEN` - Fallback token for compatibility (GitHub Actions built-in) |
| 110 | +- `APM_RUN_INFERENCE_TESTS` - When `1`, enables live inference tests in validation scripts |
| 111 | + |
| 112 | +## Performance Considerations |
| 113 | +- **Combined build-and-test**: Eliminates ~1.5m runner re-provisioning overhead by running unit tests and binary build in the same job. |
| 114 | +- **macOS as root nodes**: macOS consolidated jobs run their own unit tests and start immediately - no dependency on Linux/Windows test completion. |
| 115 | +- **Native uv caching**: `setup-uv` action with `enable-cache: true` replaces manual `actions/cache@v3` blocks. |
| 116 | +- **Targeted setup-node usage**: Node.js is only installed in `ci-runtime.yml`, macOS consolidated jobs, and integration-tests/release-validation phases (for `apm runtime setup copilot` -> npm install). |
| 117 | +- **macOS runner consolidation**: Each macOS arch has a single consolidated job (build + integration + release-validation). Intel (`build-and-validate-macos-intel`) runs on every push since Intel runners are plentiful. ARM (`build-and-validate-macos-arm`) is gated to tag/schedule/dispatch only since ARM runners are extremely scarce (2-4h+ queue waits). This avoids serial re-queuing of runners across multiple jobs. |
| 118 | +- **Unit tests skip macOS**: Python unit tests are platform-agnostic; Linux + Windows coverage is sufficient. macOS-specific validation (binary build, integration tests, release validation) still runs via the consolidated job. |
| 119 | +- **Tier 2 runs once per merged PR**, not per WIP push, since it triggers on `merge_group` only. Saves the bulk of integration minutes that the previous per-push flow burned. |
| 120 | +- UPX compression when available (reduces binary size ~50%) |
| 121 | +- Python optimization level 2 in PyInstaller |
| 122 | +- Aggressive module exclusions (tkinter, matplotlib, etc.) |
| 123 | + |
| 124 | +--- |
| 125 | +*This file was generated by APM CLI. Do not edit manually.* |
| 126 | +*To regenerate: `apm compile`* |
0 commit comments