Repository navigation
CI: resolve the environment fresh weekly, and test pull requests - #13
Merged
Merged
Conversation
The environment is open by design since v2.2.0, so a cached `conda env create` layer lets the suite report green against a resolution nobody has re-checked. The spec records why the fresh runs drop `cache-from` outright rather than trusting `no-cache` to outrank it, and why the cache-from ternary is inverted. Narrows the inherited pkgdown `docs/` rule so the spec is trackable; this repo has no pkgdown site, and the rule was only ever meant for generated output. Refs couchbits/movestore/movestore-groundcontrol#7 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Records the sequencing constraint that shapes the order: `workflow_dispatch` and `schedule` only exist for a workflow already on the default branch, so the fresh-resolution path cannot be verified until after the merge, while `pull_request` verifies straight from the PR branch. Refs couchbits/movestore/movestore-groundcontrol#7 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`test/Dockerfile` resolves conda in its own layer, and since v2.2.0 that environment is open by design - only `pandas` is pinned. So a cached layer let the suite pass against a resolution nobody had re-checked, and nothing evicted it: every push's `cache-from` reset GitHub's seven-day idle timer. Scheduled and dispatched runs now build with `no-cache` and without `cache-from`, then publish the fresh result, which also caps how stale an ordinary run can be. Pull requests were not tested at all. For a repo meant to be copied, a fork PR is the likelier origin of a change than a branch here, so `pull_request` is now a trigger and `cache-to` tolerates the 403 a fork's read-only token earns. `push` narrows to `main` so a branch with an open PR stops building twice. Refs couchbits/movestore/movestore-groundcontrol#7 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Verifying the trigger change surfaced three things in the same blind spot, so they land together. Every run warned that `actions/checkout@v4`, `docker/setup-buildx-action@v3` and `docker/build-push-action@v6` target Node 20 and are being force-migrated to Node 24. All three majors are substantively that runtime switch; `checkout` v7 additionally refuses to check out fork code under `pull_request_target` and `workflow_run`, neither of which this workflow uses. That drift - three majors on checkout - went unnoticed because nothing watches the pins, so add `dependabot.yml` for `github-actions`, grouped into one pull request. Docker is left off on purpose: the App `Dockerfile` pulls from a private GitLab registry Dependabot cannot authenticate against. `timeout-minutes: 30` because GitHub's default is 360. That was harmless while every run was a 21-second cache hit, but the weekly run resolves conda for real and unattended, and a hung solver would burn six hours every Monday. The spec also records what the first PR run proved: the `unittest` layer is cached like any other, so a green check on an unchanged tree runs no tests at all. That does not need fixing - a real change invalidates the layer - but it means the weekly run is the only periodic evidence the suite still passes. Refs couchbits/movestore/movestore-groundcontrol#7 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the CI half of
couchbits/movestore/movestore-groundcontrol#7.1. A cached conda layer could report green against an unchecked resolution
Since
v2.2.0the environment is open by design — onlypandascarries a floor and a ceiling:test/Dockerfileresolves that environment in its own layer, before the sources are copied. Thelayering is right — it is what keeps a source-only change cheap — but it means that while the layer
came from the Actions cache, the suite passed against a resolution nobody had re-checked.
Nothing evicted it, either. The cache drops entries idle for seven days, and every push read it via
cache-from, which reset the timer. In an active repo the stale layer survives untilenvironment.ymlchanges — precisely the moment nobody is watching for an unrelated dependency tohave moved underneath. The same mechanic already bit us once during rollout, when an App build pulled
its conda layer from the kaniko cache and completed "successfully" against the old environment.
Scheduled (Mondays 04:17 UTC) and manually dispatched runs now build with
no-cacheand withoutcache-from, then publish the fresh resolution — so ordinary runs test an environment at most a weekold rather than an arbitrarily old one.
2. Pull requests were never tested
The workflow triggered on
pushonly, so a pull request from a fork never ran. For a repo whosepurpose is to be copied by external contributors, that is the likelier origin of a change than a
branch in this repo.
pull_requestis now a trigger.pushnarrows tomainat the same time, so a branch here with an open PR stops building twice.Three things that are not obvious from the diff
cache-fromis dropped on fresh runs, not merely overridden byno-cache.--no-cacheoughtto outrank an imported cache, but that precedence is documented nowhere, and it is the single
assumption the whole guard rests on. Removing the import removes the question.
cache-fromternary is inverted deliberately. The natural spelling${{ FRESH == 'true' && '' || 'type=gha' }}is a trap:''is falsy in GitHub expressions, sothe
||branch always wins and both paths silently get the cache back — reinstating the exactfalse green this change exists to remove. Keeping the non-empty string on the truthy side is what
makes it work.
ignore-error=trueon the export. A fork PR runs with a read-only token and cannot write theActions cache, so
cache-to403s. Without it the run dies at the very end, after the tests havealready passed — a red check for a green suite. Import is unaffected, so fork PRs stay warm.
permissionsstayscontents: read; cache export authenticates via the Actions runtime token, notthe permissions block. The trigger is
pull_request, notpull_request_target— fork code runswith a read-only token and no secrets, which is what makes building arbitrary contributor
Dockerfiles safe.
Known limitation
GitHub disables
schedule:triggers in a repo with no commits for 60 days. A quiet repo thereforeloses the weekly canary silently — the failure mode is no signal rather than a red build, which is
the worse of the two. There is no clean fix inside Actions; it needs an external ping or a periodic
human check. Related: scheduled-run failure notifications go only to whoever last edited the cron
line.
Verification
Static gates pass locally (
actionlint, plusyqassertions pinning the trap expression). Thepull_requestrun on this PR is the first end-to-end evidence. The fresh path can only be exercisedafter merge — GitHub offers
workflow_dispatchandscheduleonly for a workflow already on thedefault branch — and the check that matters there is that
conda env createrebuilds without aCACHEDmarker.Reasoning is recorded in
docs/superpowers/specs/2026-08-04-ci-fresh-resolution-and-pr-trigger-design.md.🤖 Generated with Claude Code
Nachtrag: was das Verifizieren noch zutage gefördert hat
Der erste
pull_request-Lauf war grün — in 21 Sekunden, mit jeder SchichtCACHED, auch der,die die Tests ausführt:
Das Ticket beschreibt die Auflösung als veraltet. Tatsächlich cached auch die Test-Schicht: bei
unverändertem Baum läuft kein einziger Test. Grün heißt dann „nichts war neu zu bauen", nicht „die
Tests sind durch". Das braucht keinen eigenen Fix — eine Änderung an
python/oderenvironment.ymlinvalidiert die jeweilige Schicht und die Tests laufen wieder. Es verschiebt aberden Zweck des wöchentlichen Laufs: er ist nicht nur der einzige, der neu auflöst, sondern bei
unverändertem Baum überhaupt der einzige, der die Suite ausführt.
Drei Dinge aus derselben blinden Ecke sind gleich mit drin:
actions/checkoutv4 → v7,docker/setup-buildx-actionv3 → v4,docker/build-push-actionv6 → v7. Jeder Lauf warnte, dass diese Versionen Node 20 adressierenund zwangsweise auf Node 24 laufen. Die Warnung ist im Folgelauf verschwunden. Der einzige echte
Breaking Change —
checkoutv7 verweigert Fork-Checkout unterpull_request_targetundworkflow_run— trifft uns nicht, wir nutzen beides nicht..github/dependabot.yml, nurgithub-actions, alle Bumps in einem PR gruppiert. Drei MajorsDrift sind unbemerkt geblieben, weil nichts die Pins beobachtet. Docker bleibt bewusst aus: das
App-
Dockerfilezieht aus einer privaten GitLab-Registry, an der Dependabot sich nichtauthentifizieren kann.
timeout-minutes: 30. GitHubs Default ist 360. Egal, solange jeder Lauf ein Cache-Hit war —aber der wöchentliche Lauf löst jetzt unbeaufsichtigt echt auf, und ein hängender Solver würde
sonst jeden Montag sechs Stunden Runner-Zeit verbrennen.
Nicht enthalten, bewusst: R-Tests (es existieren keine — die CI deckt nur die Python-Hälfte ab),
environment.dev.ymlim CI-Build, und ein Issue-Report bei fehlgeschlagenemschedule-Lauf. Alledrei sind in der Spec unter Out of scope mit Begründung festgehalten.