Repository navigation
auto-publish FS.GG.Kit with a bot-authored evidence PR, replacing the manual per-version release cycle #2106
Description
Every edit to a declared kit source forces an FS.GG.Kit version bump (kit-published-coherence's
pr-arm), and main then carries a red published arm until someone tags and publishes. The
release itself is already fully mechanized; what is manual is the choreography around it. At the
current cadence — 0.24 → 0.27 in a few days, with 0.27.1 already owed behind two in-flight PRs —
that choreography is re-derived by hand every time.
Decision, already made
The maintainer has decided: auto-publish, with a bot-authored evidence PR. This item builds that.
Do not re-litigate the choice; the alternatives (hold-for-approval, or a fresh per-version backlog
row each time) were considered and rejected.
What is already mechanized, and must not be loosened
release-kit.yml fires on any tag push and already runs the entire safety posture: locked restore,
src/FS.GG.Kit/verify-package.sh (repos.lock parity, pack/content assert, materialize into a fresh
receiver root including skill-view roots/views/adopt semantics, tamper-loud check), dotnet pack,
a consumer-restore smoke test, then push to GitHub Packages followed by nuget.org via OIDC Trusted
Publishing, then receiver notification via scripts/dashboard-tick.py.
The dual-feed byte-identity is a structural property of that pipeline — it packs once and pushes
the same artifact twice, never re-packing. The manual SHA-256 comparison performed during #2093
was an audit of that guarantee, not the guarantee itself. Preserve the structure; do not replace it
with a post-hoc comparison and call that equivalent.
What is manual today
- Noticing the red
publishedarm — already redundant with the gate's own scheduled/push detection. - Deciding to tag — a judgement call, but one the maintainer has articulated as standing policy:
the version is authored in the PR and the release cuts afterward. That is the designed flow, so
the release is owed rather than optional. - Hand-writing the changelog evidence prose.
- A full
pnext-itemdispatch-and-review cycle for a two-line evidence PR whose real subject is
verifying claims that are already true by construction.
The tradeoff this accepts, stated plainly
This removes the confirm-before-every-irreversible-publish checkpoint. #2093 treated that
checkpoint as load-bearing and it worked: the worker stopped, the premises were re-verified, and the
publish proceeded on an explicit go-ahead. Automating it means pre-approving any version bump that
has already passed pr-arm as auto-publishable.
The maintainer has accepted that tradeoff. Because a published package version cannot be cleanly
unpublished, the bounds of that pre-approval must be written into the mechanism rather than left
implicit — see acceptance criteria.
Acceptance criteria
- A scheduled/push check against
maindetects an authored-but-unpublishedFS.GG.Kitversion and
auto-tags, triggeringrelease-kit.ymlwith every existing gate unchanged. If any gate is red,
it must not publish and must escalate visibly — reuse.github#2095's escalation shape (blocked
label plus one sticky marker-addressed comment carrying a streak count), not an hourly error
addressed to nobody. - The workflow opens the
registry/CHANGELOG.mdevidence entry as a bot-authored PR at publish
time, mirroring theskill-registry-autofixbot pattern, carrying the real evidence: the
release-kit.ymlrun id, both feed URLs, the resolved version, and the repository commit both
nuspecs record. Human/critic sign-off happens on that PR; a full dispatched-worker cycle is not
required. - Write the bounds of the pre-approval into the mechanism. State explicitly what it will publish
without asking (a bump that passedpr-armon a merged PR) and what it must refuse and escalate
instead. At minimum it must refuse: a MAJOR bump, a version that already exists on either feed, a
bump not reachable from a merged PR, and any run where the feeds disagree. These are the cases where
"cannot be unpublished" actually bites. - Handle the partial-publish case deliberately. If the pipeline pushes to one feed and fails before
the other, it must escalate loudly and must not retry blindly — a half-published version is a state
a human should adjudicate.#2093's worker was explicitly instructed to stop and report on this
case; encode that instruction rather than losing it. - The increment semantics must be decided by rule, not per-worker guess. Two PRs in one unpublished
window independently characterised the same bump as PATCH (.github#1933, prose-only) and argued
MINOR (.github#2080, receiver-visible). Both converged on 0.27.1 for collision avoidance, which
settles which number but not what it means. State the rule the gate enforces. - The mechanism must be idempotent and must not race itself: two triggers in the same window must not
produce two tags or two evidence PRs.
Verification
- Demonstrate against a real bump —
0.27.1is owed right now and is the natural fixture, exactly as
PR registry: re-digest stale skill rows (auto) #2078 was for.github#2095. Do not verify against a hypothetical. - Show the refusal paths firing: a version already on a feed, and a red gate.
- Show the evidence PR opening with correct, checkable content, and confirm the published artifact is
byte-identical across feeds by the structural route rather than a bolted-on comparison.
Note on sequencing
FS.GG.Kit 0.27.1 is owed as soon as .github#1933 (PR #2100) or .github#2080 (PR #2101) lands.
Until this mechanism exists, that release is manual. Whoever takes this should decide whether to
publish 0.27.1 by hand first and then build, or build and let the mechanism cut it — and say which.
Paths: .github/workflows scripts registry/CHANGELOG.md docs/adr .github/workflows/** scripts/** docs/adr/** work/2106-auto-publish/** readiness/2106-auto-publish/** tests/kit-auto-publish/**
Class: hardening
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
EHotwagner commentedon Aug 2, 2026
Evidence from
.github#2107(PR #2110, merge commit77e463f479183343e586d9fae8465d16b08b5438): thepublishedarm's stale-file list grew from 4 to 6 entries across this merge (parent54ec3b0: 4 files; merge commit: 4 +pnext-item/SKILL.md+pnext-item/references/deep-detail.md, since that PR edited both). Same root cause this issue already tracks — FS.GG.Kit 0.27.0 published, 0.28.0 authored-but-unpublished — not a new cause, just a growing evidence set for whoever cuts the eventual publish.Parent run: https://github.com/FS-GG/.github/actions/runs/30743640244
Merge-commit run: https://github.com/FS-GG/.github/actions/runs/30744146327
EHotwagner commentedon Aug 3, 2026
Mandatory delivery-route decision
Decision maker: Codex drive-board host
Decision:
SDD-requiredRationale: This automates an irreversible dual-feed publish, defines pre-approval/refusal policy, partial-publish recovery, version semantics, concurrency/idempotency, bot evidence PRs, and sticky escalation. It is a high-impact workflow/state-machine change with external side effects and several failure boundaries; prose-first local implementation is not an acceptable route.
This decision is mandatory for dispatch. Material implementation may not begin until the SDD workspace specifies the state machine, refusal and partial-publish cases, idempotency/concurrency contract, evidence obligations, and verification readiness. The worker must follow the publishing/deployment safety gate and must not broaden authorization beyond the issue’s explicit standing policy.
EHotwagner commentedon Aug 3, 2026
godwit-d2f0 → curlew-07c9
.github#2155 narrowed its held touch-set to work/2155-external-owner-identity/ and readiness/2155-external-owner-identity/ plus its declared coordination code/tests; live overlap is now clear.
EHotwagner commentedon Aug 3, 2026
Handoff: committed fail-closed SDD/state-machine slice at 833fb6b. It includes offline refusal/partial/eligible fixtures,
implementationReadySDD artifacts, and #2095-style sticky escalation scaffolding. Remaining acceptance: authenticated read-only dual-feed existence/agreement observation; merged-PR/pr-arm and release-run provenance; then guarded tag and idempotent evidence-PR writes. The current live path deliberately refuses unknown observations and performs no irreversible write.EHotwagner commentedon Aug 3, 2026
finch-8656 → shrike-b180
your expired claim on .github#2106 was collected — worker 'finch-8656' has taken the item. Stop working it.
9 remaining items
EHotwagner commentedon Aug 14, 2026
The expected candidate-not-next-patch auto-publish refusal is no longer an active blocker. The bounded 0.57.0 saga completed from exact source 5fd45a7: prepare 31842081260; observation-only resumes 31842740819, 31842743671, and 31842745926; promotion 31842920120; stable release https://github.com/FS-GG/.github/releases/tag/coherent-set/v0.57.0; adoption merged in #2628 at 5542dbe. Closing this stale same-class escalation; future auto-publish failures should open fresh evidence only when an active condition remains.
docs(review): gate-inversion evidence must show CI RUNS the gate, and…
docs: record FS.GG.Kit 0.76.0 publish evidence (#2633)