[HOLD-for-9.0.0][skip-runtime-e2e] docs(decisions): canonical /decisions verdict values #55
Workflow file for this run
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: Definition of Done | |
| # Enforces CLAUDE.md HARD RULE #0: a user-facing feature is not done until | |
| # demonstrated through its actual runtime. See axonflow-claude-plugin#59 | |
| # for the doctrine + lint-no-mocks rationale. | |
| on: | |
| pull_request: | |
| # Trim out non-diff-changing event types: dropped `edited` (title/body | |
| # edit re-runs the gate without any code change). `reopened` retained for | |
| # PRs that were closed and reopened with new commits. | |
| types: [opened, synchronize, reopened] | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| lint-no-mocks-in-runtime-e2e: | |
| name: Lint — no mocks in runtime-e2e/ | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Run lint | |
| run: | | |
| if [ -x scripts/lint-no-mocks-in-runtime-e2e.sh ]; then | |
| ./scripts/lint-no-mocks-in-runtime-e2e.sh | |
| else | |
| echo "lint-no-mocks-in-runtime-e2e.sh not present — skipping (older branch)." | |
| fi | |
| runtime-e2e-required: | |
| name: Runtime E2E required for user-facing changes | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Detect user-facing surface changes | |
| id: detect | |
| env: | |
| BASE: ${{ github.event.pull_request.base.sha }} | |
| HEAD: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| set -uo pipefail | |
| # Java SDK user-facing surface: the published library code under | |
| # src/main/java/, the Maven manifest pom.xml that downstream | |
| # consumers depend on, and runnable example sources under examples/. | |
| USER_FACING_GLOBS=( | |
| 'src/main/java/' | |
| 'pom.xml' | |
| 'examples/' | |
| ) | |
| CHANGED=$(git diff --name-only "$BASE" "$HEAD" || true) | |
| echo "Changed files in PR:" >&2 | |
| printf ' %s\n' $CHANGED >&2 | |
| MATCHED="" | |
| for f in $CHANGED; do | |
| for pat in "${USER_FACING_GLOBS[@]}"; do | |
| case "$f" in | |
| "$pat"*|*"/$pat"*) | |
| MATCHED="$MATCHED $f" | |
| break | |
| ;; | |
| esac | |
| done | |
| done | |
| RUNTIME_E2E_TOUCHED=$(echo "$CHANGED" | grep -c '^runtime-e2e/' || true) | |
| { | |
| echo "user_facing_changed=$([ -n "$MATCHED" ] && echo true || echo false)" | |
| echo "runtime_e2e_touched=$RUNTIME_E2E_TOUCHED" | |
| } >> "$GITHUB_OUTPUT" | |
| if [ -n "$MATCHED" ]; then | |
| echo "User-facing files changed:" >&2 | |
| for f in $MATCHED; do echo " - $f" >&2; done | |
| fi | |
| - name: Check escape-hatch justification | |
| id: hatch | |
| if: steps.detect.outputs.user_facing_changed == 'true' && steps.detect.outputs.runtime_e2e_touched == '0' | |
| env: | |
| PR_TITLE: ${{ github.event.pull_request.title }} | |
| PR_BODY: ${{ github.event.pull_request.body }} | |
| run: | | |
| set -uo pipefail | |
| if [[ "$PR_TITLE" == *"[skip-runtime-e2e]"* ]]; then | |
| if echo "$PR_BODY" | grep -q '## Skip-runtime-e2e justification'; then | |
| echo "Escape hatch active." >&2 | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "::error::PR title carries [skip-runtime-e2e] but body has no '## Skip-runtime-e2e justification' section." | |
| exit 1 | |
| fi | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Enforce runtime-e2e/ presence | |
| if: steps.detect.outputs.user_facing_changed == 'true' && steps.detect.outputs.runtime_e2e_touched == '0' && steps.hatch.outputs.skip != 'true' | |
| run: | | |
| cat <<'EOF' >&2 | |
| ::error::This PR touches real SDK code (src/main/java/, pom.xml, examples/) without runtime-e2e/ test | |
| but does not add or update any runtime-e2e/ test in the same PR. | |
| Per CLAUDE.md HARD RULE #0: | |
| A user-facing feature is not done until you have demonstrated it | |
| working through its actual runtime — real SDK class loaded by a | |
| real JVM, real HTTP request against a real running AxonFlow agent. | |
| Mocks, stubs, WireMock, MockWebServer, capture-stub harnesses do | |
| NOT count as runtime proof. | |
| To resolve, do ONE of: | |
| 1. Add a test under runtime-e2e/<feature>/ that invokes the | |
| feature through the actual user-facing surface (real | |
| AxonFlow client class wired to a real running agent). | |
| 2. If genuinely internal (build / deps / lint baseline / docs), | |
| add `[skip-runtime-e2e]` to PR title AND a | |
| `## Skip-runtime-e2e justification` section to PR body. | |
| See: axonflow-internal-docs/engineering/E2E_EXAMPLES_TESTING_WORKFLOW.md | |
| EOF | |
| exit 1 | |
| - name: All clear | |
| if: steps.detect.outputs.user_facing_changed == 'false' || steps.detect.outputs.runtime_e2e_touched != '0' || steps.hatch.outputs.skip == 'true' | |
| run: | | |
| if [ "${{ steps.detect.outputs.user_facing_changed }}" = 'false' ]; then | |
| echo "No user-facing surface changed. Gate not applicable." >&2 | |
| elif [ "${{ steps.detect.outputs.runtime_e2e_touched }}" != '0' ]; then | |
| echo "User-facing change detected and runtime-e2e/ updated in same PR. ✓" >&2 | |
| else | |
| echo "Escape hatch active with valid justification. ✓" >&2 | |
| fi |