From ad83982e921f665ef023b07e2ab8ad39aca1bce9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 12:11:31 +0000 Subject: [PATCH 1/3] ci: build changed registry definitions on the pull request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ci.yml lints, builds and tests the TypeScript packages; nothing there reads registry/*.yaml. A definition naming a branch or docs_path that does not exist passes review and CI unchallenged, then fails at 06:00 UTC in the nightly registry-update — after the PR that introduced it is merged and out of mind. That is the same shape as the sanity breakage that hid for four nights: the check that would have caught it ran nowhere near the change. #133 made it concrete. Two new definitions arrived with zero check runs, so verifying them meant building both by hand. This builds the definitions a PR adds or modifies, on the PR. Only changed ones, so cost tracks the diff rather than the 113-definition registry. Verified before committing, since a validator that passes broken input is worse than none: - A nonexistent git ref exits 1. - A nonexistent docs_path exits 1 rather than producing an empty package, which was the failure mode worth ruling out. - Name extraction handles a name that differs from its filename (registry/hex/phoenix.yaml is "phoenix"), quoted names, and a missing name: field. - The diff detection returns exactly the two definitions from #133 and excludes deletions. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NBQQpA86yYzwJUiVz8ph2R --- .github/workflows/registry-validate.yml | 111 ++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 .github/workflows/registry-validate.yml diff --git a/.github/workflows/registry-validate.yml b/.github/workflows/registry-validate.yml new file mode 100644 index 0000000..d196629 --- /dev/null +++ b/.github/workflows/registry-validate.yml @@ -0,0 +1,111 @@ +name: Registry Validate + +# Builds the registry definitions a pull request adds or changes. +# +# ci.yml lints, builds and tests the TypeScript packages; nothing there reads +# registry/*.yaml. A definition naming a branch or docs_path that does not +# exist therefore passes review and CI, and first fails at 06:00 UTC in the +# nightly registry-update — long after the PR that introduced it is merged and +# out of mind. This closes that gap by building the changed definitions on the +# pull request itself. +# +# Only changed definitions are built, so cost scales with the diff rather than +# with the 113-and-growing registry. + +on: + pull_request: + branches: + - main + paths: + - 'registry/**/*.yaml' + - 'registry/**/*.yml' + +permissions: {} + +concurrency: + group: registry-validate-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + build-changed: + name: Build changed definitions + runs-on: ubuntu-latest + # A definition can pull a large documentation repository; godot builds + # ~8M tokens from 3.5k files. Generous, but bounded. + timeout-minutes: 45 + + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v6 + with: + version: 10.27.0 + + - name: Setup Node.js + uses: actions/setup-node@v7 + with: + node-version: '22' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build each changed definition + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + set -euo pipefail + + # Added or modified only: a deleted definition has nothing to build. + changed=$(git diff --name-only --diff-filter=AM "$BASE_SHA" "$HEAD_SHA" \ + -- 'registry/**/*.yaml' 'registry/**/*.yml') + + if [ -z "$changed" ]; then + echo "No definition files added or modified." + exit 0 + fi + + echo "Changed definition files:" + echo "$changed" | sed 's/^/ /' + echo + + failed="" + built=0 + + while IFS= read -r file; do + [ -n "$file" ] || continue + + # The CLI selects by the definition's `name` field, which need not + # match the filename (registry/hex/phoenix.yaml is "phoenix"). + name=$(sed -n 's/^name:[[:space:]]*//p' "$file" | head -1 | tr -d '"'"'"'' | tr -d '\r') + if [ -z "$name" ]; then + echo "::error file=$file::no top-level 'name:' field found" + failed="${failed} ${file}" + continue + fi + + echo "::group::Building ${name} (${file})" + if pnpm --filter @neuledge/registry test-registry test "$name"; then + built=$((built + 1)) + echo "::endgroup::" + else + echo "::endgroup::" + echo "::error file=$file::definition '${name}' failed to build" + failed="${failed} ${name}" + fi + done <<< "$changed" + + echo + if [ -n "$failed" ]; then + echo "Failed to build:${failed}" + exit 1 + fi + echo "Built ${built} definition(s) successfully." From 75ea47d9e27e5c239de9e49b62a757d2b698df5f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 12:12:43 +0000 Subject: [PATCH 2/3] test: temporary probe to prove Registry Validate fires and fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a definition naming a branch that does not exist. The new workflow must trigger on it and go red. Reverted in the next commit — this exists only to prove the wiring, which #134 cannot test on itself since it changes no registry files. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NBQQpA86yYzwJUiVz8ph2R --- registry/ci-probe-delete-me/ci-probe-delete-me.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 registry/ci-probe-delete-me/ci-probe-delete-me.yaml diff --git a/registry/ci-probe-delete-me/ci-probe-delete-me.yaml b/registry/ci-probe-delete-me/ci-probe-delete-me.yaml new file mode 100644 index 0000000..720d643 --- /dev/null +++ b/registry/ci-probe-delete-me/ci-probe-delete-me.yaml @@ -0,0 +1,8 @@ +name: ci-probe-delete-me +description: "Temporary probe: points at a branch that does not exist. Registry Validate must go red on this. Reverted in the next commit." +repository: https://github.com/godotengine/godot-docs +source: + type: git + url: https://github.com/godotengine/godot-docs + ref: this-branch-does-not-exist-xyz + docs_path: tutorials/scripting/gdscript From 856434fc2cd12ede3d5c5551eed50c71e8737e5f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 12:13:49 +0000 Subject: [PATCH 3/3] test: remove the Registry Validate probe The probe did its job. On the previous commit the workflow triggered, resolved the definition name, and failed with: Git clone failed: fatal: Remote branch this-branch-does-not-exist-xyz not found in upstream origin ##[error]definition 'ci-probe-delete-me' failed to build Process completed with exit code 1 That is the failure surfacing for the right reason rather than incidentally, which is the only version of this check worth having. The two commits are kept rather than squashed away so the evidence stays in the branch history. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NBQQpA86yYzwJUiVz8ph2R --- registry/ci-probe-delete-me/ci-probe-delete-me.yaml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 registry/ci-probe-delete-me/ci-probe-delete-me.yaml diff --git a/registry/ci-probe-delete-me/ci-probe-delete-me.yaml b/registry/ci-probe-delete-me/ci-probe-delete-me.yaml deleted file mode 100644 index 720d643..0000000 --- a/registry/ci-probe-delete-me/ci-probe-delete-me.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: ci-probe-delete-me -description: "Temporary probe: points at a branch that does not exist. Registry Validate must go red on this. Reverted in the next commit." -repository: https://github.com/godotengine/godot-docs -source: - type: git - url: https://github.com/godotengine/godot-docs - ref: this-branch-does-not-exist-xyz - docs_path: tutorials/scripting/gdscript