Commit Graph
8 Commits
Author SHA1 Message Date
mathias 6838baa071 fix(ci): gate the release-bump commit — nothing has ever tested it
CI / Check / Test (push) Successful in 3s
CI / Tag release (push) Successful in 1s
Found from the other end: the koala cluster's CIHeadUncovered{repo=skills}
alert had been firing for 85 hours, and it is a true positive.

    mathias/skills main HEAD   f031c2b
    workflow runs for that sha  0

Not a one-off. The previous release-bump commit has the same property:

    6cc224f  chore(release): plugin.json version 0.19.4  ->  0 runs
    f031c2b  chore(release): plugin.json version 0.19.5  ->  0 runs

The `tag` job pushes the manifest bump itself with secrets.GITEA_TOKEN, and a
push authenticated with the Actions token does not trigger workflows -- that is
deliberate platform behaviour to stop CI recursing. The `Skip-Release: true`
trailer stops the TAGGER recursing and works; nothing stopped the whole run,
`gate` included, from never firing on that commit.

So after every release, main's HEAD is a commit no CI has seen, until an
unrelated human push moves it. CIHeadUncovered therefore cannot clear on its
own -- and an alert that can only be cleared by doing something unrelated is
worse than a noisy one, because it teaches the reader that red is the normal
state of that rule.

The commit is not cosmetic either. plugin.json's version is what Claude Code
gates plugin updates on, `task check` asserts it is not behind the latest tag,
and the sed-and-retry logic that writes it already shipped a mismatched
manifest once -- v0.10.0 tagged with the manifest still reading 0.9.0, per the
comment above that very loop.

Fix: run `task check` on the bump commit before pushing it. The commit is
produced in that step, so it can be validated in that step -- one check instead
of a second full CI run, and no recursion risk to reintroduce.

Considered and rejected: re-triggering CI with a different credential after the
push (costs a full run per release and brings back what the token behaviour
exists to prevent), and teaching CIHeadUncovered to ignore manifest-only
commits (narrowing the measure to fit the system, and it would hide a real gap
too).

The assertion in tests/ci_gate_test.sh had to be anchored with ^[^#]*: the tag
job's own prose says "`task check` asserts the manifest is not behind the
latest tag", so a bare grep matched the comment explaining the problem and
reported the problem fixed.

Closes #46.
2026-09-11 11:11:16 +02:00
mathias d7775aac57 fix(ci): tag and bump separately — a queued run pushed a stale main
CI / Check / Test (push) Successful in 1s
CI / Tag release (push) Successful in 1s
Three runs failed with `! [rejected] HEAD -> main (non-fast-forward)`. The
runner is maxParallel=1 and shared with mathias/infra, so those jobs started
five minutes and three commits after their own push. The tagger checked out
its commit and pushed that stale HEAD to main, which main had long left behind.

My own change made it worse: pairing the manifest bump and the tag in a single
`git push` turned a partial failure into a total one, so no tag was created
either. Except once — v0.10.0 landed through the no-bump-needed branch while
the manifest stayed at 0.9.0, which is precisely the "installed hosts never
see the release" state, and which #34's ordering check then caught on main.

The tag now goes up first and alone: it names the commit this run checked out
and cannot be rejected however far main has moved. The bump is a separate
concern that must land on whatever main is NOW, so it re-fetches, rebuilds the
commit on origin/main and retries up to three times, and steps aside entirely
if a later run has already bumped past it.

plugin.json is set to 0.10.0 in this commit so the gate can pass at all — main
was red on manifest-behind-tag, which would have blocked the tag job that fixes
the tagger.

Refs #22
Bump-Type: patch
2026-08-29 11:25:20 +02:00
mathias 3112b4ce92 chore(ci): gate the release tagger on check + test
CI / Check / Test (push) Successful in 0s
CI / Tag release (push) Successful in 0s
The repo had a `task check` structure gate and a 28-case shell test suite
that nothing ever ran. The only workflow auto-tagged every push to main, so
CI reported green having tested nothing — a gate that fails open, and the
reason `mathias/skills` shows up as repository-blocked in the estate backlog
classification.

release.yml becomes ci.yml with two jobs: `gate` runs check + test on every
push and PR; `tag` keeps the existing semver-from-trailer logic but declares
`needs: gate`, so a red check cannot ship a tag. The pull_request trigger
also gives `tbd_ship` a CI run to read on a branch head — without one it
fails closed and never merges (#22).

The tagger now pushes the manifest bump commit and the tag in a single
`git push`. Two pushes left a window where the gate ran `task check` on the
bump commit before the tag existed, and the manifest/tag parity assertion
would fail on a commit that was in fact correct.

tests/ci_gate_test.sh pins the wiring: PR trigger present, both tasks run,
tag needs gate, no second ungated workflow file.

Refs: #22
Bump-Type: minor
2026-08-29 09:46:10 +02:00
mathiasandClaude Opus 5 e2a312d05e fix(ci): anchor the release-skip marker to a trailer, and test it
release / tag (push) Successful in 1s
The tagger searched the entire commit message for a bracketed marker as a
substring. The commit that introduced the manifest-bump step described that
marker in its own body — so the tagger read its own documentation as an
instruction and skipped the release. Run 15 reported success with no tag, no
manifest bump and no error. Same failure family as everything else in this
sweep: the wrong thing happened silently.

The rule is now a git trailer matched anchored to its own line, consistent
with Bump-Type, and it lives in bin/should-skip-release rather than untested
inside YAML. tests/release_skip_test.sh pins six cases, including the exact
regression: a message that spells the marker out in prose must still tag.

A marker you cannot mention without triggering is a footgun, not a mechanism.

Bump-Type: patch

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m
2026-08-23 14:39:31 +02:00
mathiasandClaude Opus 5 78b9b59eca docs+ci: document the plugin path, bump plugin.json version on release
release / tag (push) Successful in 1s
CI now writes the computed semver into .claude-plugin/plugin.json before
tagging, committed with [skip-release] so it does not re-trigger the tagger.
Claude Code gates plugin updates on that field: without the bump, installed
hosts never see a new tag no matter how many releases go out. `task check`
enforces manifest/tag equality so the two cannot silently diverge.

Docs rewritten around the two delivery paths, and the checkout location is now
stated as load-bearing rather than incidental: SKILLS_CHECKOUT_DIR defaults to
~/.local/share/skills because that is host-local and outside any synced
directory. The previous docs told you to clone into ~/dev, which on this fleet
is an iCloud folder shared by two Macs spanning two path roots — a git working
tree with concurrent writers, and absolute links that are broken on one side by
construction. That advice is what #23 is about; it is now inverted with the
reason attached.

Antigravity and Vibe removed from the docs along with their targets.

Bump-Type: patch

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m
2026-08-23 14:35:38 +02:00
mathias 1256653319 fix(ci): release.yml tag job dies whenever a commit has no Bump-Type footer (skills#8)
release / tag (push) Successful in 1s
set -euo pipefail + `... | grep -iE '^Bump-Type:' | head -1 | awk ...`
inside `bump=$(...)`: when the last commit has no Bump-Type footer (the
normal default-to-patch case), grep exits 1 on no-match. Under
pipefail, that propagates as the whole pipeline's exit status even
though head/awk both succeed -- set -e then kills the script before it
ever reaches the case statement. Broke on every push since 2026-06-22
once a footer-less commit landed after the last one that happened to
carry a Bump-Type line. Appended `|| true` to swallow the expected
no-match case.
2026-07-24 15:44:55 +02:00
mathias 5a2bef35c1 fix(ci): runs-on self-hosted to match koala runner labels
release / tag (push) Successful in 1s
The koala act_runner has labels [self-hosted, linux, amd64]. The
default ubuntu-latest label doesn't match, so the release workflow
silently produced zero runs on every push. Matches the convention
used by hyperguild + infra workflows.

Runner is offline at time of this commit — bring it up on koala via
the act_runner systemd unit before expecting tags to appear.

[skip-release]
2026-05-24 20:52:26 +02:00
mathias d6a71e370e chore: bootstrap skills library — 19 skills + installer + CI auto-tag
release / tag (push) Has been cancelled
Phase 1 of mathias/skills extraction (infra#62 Track D — homelab
next-step plan addendum). Imports ~/dev/.skills/ verbatim (19 skill
dirs + SKILLS_INDEX.md) and adds the installation surface:

- Taskfile.yml — install / update / list / release / check targets
- install.sh — bootstrap installer for hosts without Task. Idempotent
  symlink wirer; default checkout at ~/.local/share/skills/ on every
  host; SKILLS_REF env var pins a tag (default: main).
- .gitea/workflows/release.yml — auto-tag every push to main by
  Bump-Type footer (major/minor/patch, default patch). Skipped when
  commit contains [skip-release].
- README — usage, versioning, contribution flow, secret-hygiene rule.

Phase 1 wires Claude Code only (~/.claude/skills/<name> global +
<repo>/.claude/skills/<name> per-repo). Phase 2 adds Crush, opencode,
antigravity, and gitea-resident agents (cobalt-dingo, agentsquad)
once their skill conventions are researched.

Public repo, markdown-only — no secrets, no client names. Verified
via pre-push grep before initial push.

[skip-release]
2026-05-24 14:59:54 +02:00