Skip to content

Fix initialisation guard: single sentinel + shared action, fail loud on silent-green CI#3

Merged
annefou merged 1 commit into
mainfrom
fix/initialisation-guard-sentinel
Jun 9, 2026
Merged

Fix initialisation guard: single sentinel + shared action, fail loud on silent-green CI#3
annefou merged 1 commit into
mainfrom
fix/initialisation-guard-sentinel

Conversation

@annefou

@annefou annefou commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Why

A real replication built from this template (j34ni/forrt-replication-zarr-consistency) published a nanopub chain and minted a Zenodo DOI on top of CI that had never actually run — the smoke run finished green in ~8 s, skipping pixi + the whole Snakefile pipeline, and the Docker workflow skipped Build and push on release (so docker run ghcr.io/...:latest from the README fails — no image was ever pushed).

Root cause

The question "is this template initialised → should the pipeline run?" was answered five different ways — the three workflows, the /init-template skill, and CLAUDE.md's first-run guard — each a repo-wide grep '{{[A-Z_]\+}}' with a different exclusion list. Two problems:

  1. False positive. The template legitimately ships literal {{TOKEN}} examples in docs/ (forrt-form-fields.md, …) and .claude/skills/ (they document the token system). The grep matches those, decides "not initialised", and skips — forever, even in a finished repo.
  2. Drift. Five copies → they diverge. Someone fixed the Jupyter Book guard downstream but not CI/Docker, so the book deployed while CI/Docker stayed silently green-but-empty.
  3. Silent green. A skipped job reports success, so nothing surfaces the problem.

Fix

  • .template-uninitialised sentinel — the single state signal. No more token-grepping to decide initialisation. /init-template deletes it as its final step, which activates the workflows.
  • .github/actions/check-ready — one composite action (sentinel + notebooks/*.py scaffold check) that all three workflows call. They can't drift again.
  • Tripwire — if nanopubs/PUBLISHED.md records real published nanopub URIs but the guard would still skip, the run fails loudly instead of passing green. This directly catches the failure mode above.
  • CLAUDE.md first-run guard now checks the sentinel.
  • README updated to describe the shared guard + the fail-loud behaviour.

Verification

YAML validated; logic simulated across four states:

State Result
Uninitialised template (sentinel present, example URIs) skip ✓
Initialised + scaffold notebooks + real published URIs fail loudly
Initialised + real notebooks run ✓
Initialised + scaffold + not-yet-published skip ✓

The template's own PUBLISHED.md carries only np/RA… ellipsis examples (and the template repo is itself tagged), so the tripwire keys on real URIs (np/RA + ≥10 id chars) and does not fire on this repo.

Note for downstream repos

Repos already generated from the template (e.g. Jean's) won't get this retroactively — they need the same guard backported, plus a fresh release to actually publish the Docker image to GHCR.

🤖 Generated with Claude Code

…on silent-green

The "is this template initialised, should CI run?" question was answered by
five divergent copies of a repo-wide `{{...}}` grep (3 workflows, the
/init-template skill, and CLAUDE.md), each with a different exclusion list.
They drifted, and — worse — the grep false-positives on the template's OWN
literal token examples in docs/ and .claude/, so a fully-finished replication
silently skipped its CI/Docker pipelines while reporting green.

Root-cause fix:

- Add a `.template-uninitialised` sentinel as the ONE state signal. No more
  token-grepping to decide initialisation state.
- Add `.github/actions/check-ready` composite action as the single source of
  truth (sentinel check + notebooks/*.py scaffold check). All three workflows
  call it, so they can't drift again.
- Tripwire: if the repo records real published nanopub URIs in
  nanopubs/PUBLISHED.md but the guard would still skip, fail the run loudly
  instead of passing green. This is the check that turns the silent-green
  failure mode into a visible one.
- CLAUDE.md first-run guard now checks the sentinel, not a {{...}} grep.
- /init-template deletes the sentinel as its final step (activating the
  workflows); README updated to describe the shared guard.

Logic verified across four states: uninitialised template (skip), finished+
scaffold+published (fail), initialised+real (run), initialised+scaffold+
unpublished (skip).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@annefou annefou merged commit 0f35234 into main Jun 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant