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
151 changes: 18 additions & 133 deletions .github/workflows/blink_parity.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
name: Blink Parity

# Runs blink and the ECS in this repository on the same real codebase (full
# rector-src) and fails if blink's output differs from ECS (psr12 + common) on
# any file. This is the 1:1 parity gate - it stays red until blink reproduces
# ECS exactly.
# Runs blink (--blink) and the PHP ECS engine over the same real-world corpora
# and fails when blink's output diverges beyond each corpus's ratchet threshold.
# One matrix entry per corpus; thresholds and sets live in blink/parity/corpora/.
# The company goal is 0% divergence on every corpus, so the thresholds only ever
# go down. The job summary lists every differing file grouped by the ECS checker
# that caused it, so the remaining gap stays visible.

on:
pull_request:
Expand All @@ -16,147 +18,30 @@ on:
workflow_dispatch: null

jobs:
blink-parity:
parity:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
corpus:
- rector-src
- mautic
- laravel
- rector
name: "parity: ${{ matrix.corpus }}"
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: "1.26.6"

- name: Build blink
working-directory: blink
run: go build -o /tmp/blink .

- uses: shivammathur/setup-php@v2
with:
php-version: "8.4"
coverage: none

# installs this repository's ECS so parity runs against the code being shipped
- uses: "ramsey/composer-install@v4"

- name: Fetch a real codebase sample
run: |
git clone --depth 1 https://github.com/rectorphp/rector-src.git /tmp/rector
# full rector-src tree; .php.inc fixtures are skipped by the *.php find below
mkdir -p /tmp/sample
cp -r /tmp/rector/src /tmp/rector/rules /tmp/rector/tests /tmp/sample/
cp -r /tmp/sample /tmp/ours
cp -r /tmp/sample /tmp/ecs

- name: Run blink
run: /tmp/blink --fix /tmp/ours || true

- name: Build the local ECS config
run: |
cat > /tmp/ecs.php <<'PHP'
<?php

declare(strict_types=1);

use Symplify\EasyCodingStandard\Config\ECSConfig;

return ECSConfig::configure()
->withPreparedSets(psr12: true, common: true);
PHP

- name: Run the local ECS
run: bin/ecs check /tmp/ecs --fix --no-progress-bar --config /tmp/ecs.php || true

- name: Rank missing fixers (data-driven backlog)
run: |
# what ECS would apply on the pristine sample, as JSON
bin/ecs check /tmp/sample --output-format=json --config /tmp/ecs.php > /tmp/ecs.json 2>/dev/null || true
# fixers we already implement
/tmp/blink list-checkers | sed 's/^[[:space:]]*-[[:space:]]*//; /Registered/d' | sort -u > /tmp/impl.txt
# count applied checkers across files, most frequent first
jq -r '[.files[]?.diffs[]?.applied_checkers[]?] | group_by(.) | map("\(length) \(.[0])") | .[]' /tmp/ecs.json 2>/dev/null | sort -rn > /tmp/counts.txt || true
{
echo "## Backlog: ECS fixers not yet in blink, ranked by frequency on the sample"
echo ""
echo "| fixer | files |"
echo "|---|---|"
} >> "$GITHUB_STEP_SUMMARY"
n=0
while read -r count chk; do
[ "$n" -ge 25 ] && break
if ! grep -qxF "$chk" /tmp/impl.txt; then
echo "| \`$chk\` | $count |" >> "$GITHUB_STEP_SUMMARY"
n=$((n + 1))
fi
done < /tmp/counts.txt
if [ "$n" -eq 0 ]; then
echo "| (no data - check the ECS JSON shape) | |" >> "$GITHUB_STEP_SUMMARY"
fi
# stdout diagnostics (the summary table is not fetchable via CLI)
echo "=== implemented: $(wc -l < /tmp/impl.txt) | ecs.json bytes: $(wc -c < /tmp/ecs.json) ==="
echo "=== top applied checkers, raw (before excluding implemented) ==="
head -20 /tmp/counts.txt || true

- name: Compare outputs
run: |
total=0
differ=0
for f in $(cd /tmp/ours && find . -name '*.php'); do
total=$((total + 1))
if ! diff -q "/tmp/ours/$f" "/tmp/ecs/$f" >/dev/null 2>&1; then
differ=$((differ + 1))
fi
done
same=$((total - differ))
{
echo "## blink vs ECS (psr12 + common) on full rector-src"
echo ""
echo "| metric | value |"
echo "|---|---|"
echo "| files | $total |"
echo "| identical output | $same |"
echo "| differing output | $differ |"
echo ""
echo "This is the 1:1 parity gate: it fails while any file differs from ECS."
} >> "$GITHUB_STEP_SUMMARY"
echo "identical=$same differing=$differ of $total"

# Per differing file: which rules ECS applied vs blink, and the
# snippet they differ on. ECS applied checkers come from the JSON
# captured on the pristine sample; blink's from a dry-run check.
echo "### Divergences ($differ files): applied rules + diff" >> "$GITHUB_STEP_SUMMARY"
echo ""
echo "=== Divergences ($differ files) ==="
export LC_ALL=C
for f in $(cd /tmp/ours && find . -name '*.php' | sort); do
diff -q "/tmp/ours/$f" "/tmp/ecs/$f" >/dev/null 2>&1 && continue
rel=${f#./}
abs="/tmp/sample/$rel"
ecs_rules=$(jq -r --arg k "$abs" '.files[$k].diffs[]?.applied_checkers[]?' /tmp/ecs.json 2>/dev/null | sed -E 's#.*\\##' | sort -u)
go_rules=$(/tmp/blink "$abs" 2>/dev/null | sed -n 's/^[[:space:]]*\*[[:space:]]//p' | sed -E 's#.*\\##' | sort -u)
ecs_only=$(comm -23 <(printf '%s\n' "$ecs_rules") <(printf '%s\n' "$go_rules") | grep -v '^$' | paste -sd, - || true)
go_only=$(comm -13 <(printf '%s\n' "$ecs_rules") <(printf '%s\n' "$go_rules") | grep -v '^$' | paste -sd, - || true)
# stdout (CI log): file + which rules differ + the diff
echo ""
echo "--- $rel"
echo " ECS applied, blink did not: ${ecs_only:-(none)}"
echo " blink applied, ECS did not: ${go_only:-(none)}"
diff "/tmp/ours/$f" "/tmp/ecs/$f" | sed 's/^/ /' | head -40 || true
# job summary (rich, collapsible)
{
echo ""
echo "<details><summary>$rel</summary>"
echo ""
echo "- **ECS applied, blink did not:** ${ecs_only:-(none)}"
echo "- **blink applied, ECS did not:** ${go_only:-(none)}"
echo ""
echo '```diff'
diff "/tmp/ours/$f" "/tmp/ecs/$f" | head -40 || true
echo '```'
echo "</details>"
} >> "$GITHUB_STEP_SUMMARY"
done

# fail when blink output does not match ECS
if [ "$differ" -gt 0 ]; then
echo "::error::blink output differs from ECS on $differ of $total files"
exit 1
fi
- name: "Parity ${{ matrix.corpus }}"
run: blink/parity/run.sh "blink/parity/corpora/${{ matrix.corpus }}.json"
151 changes: 0 additions & 151 deletions .github/workflows/blink_parity_laravel.yaml

This file was deleted.

Loading
Loading