Files changed: - CHANGES.md - VERSION - instructions/dev/publish-and-ci.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
5.4 KiB
type, name, description
| type | name | description |
|---|---|---|
| types/instruction.md | publish-and-ci | How a stack change is published and how its CI run is waited for - the local checks first, tools/wikitool publish, reading the runs through the authenticated Gitea connection rather than curl, how long to wait, when to give up, and why a red run means the build phase is not over. |
Publish a stack change and wait for its CI run
The local checks cover what they cover on this machine; CI covers the same checks plus a full
setup-instance.md replay against a fresh dist export (.gitea/workflows/ci.yml). A green run
on the published commit - and, for a converter change, a green Converters run (step 3) - is
therefore the end of the checked stretch of a work package, not a
formality after it - which is why waiting for it belongs to the phase that wrote the code
(stack-build), and a red run sends the work back there rather than into the closing phase.
When to run
stack-build, every time it publishes - its last step.stack-close, when its own pull-through of a stale document publishes something of its own (that skill's step 3 says when).
Steps
-
Run the local checks, explicitly rather than assumed:
tools/wikitool docs verify tools/wikitool instructions verifyplus the relevant
pytestrun intools/(testing-conventions.md). A red check here is fixed before anything is published. -
Publish with
tools/wikitool publish. The gates apply as everywhere (AGENTS.md § Gates); an exit 42 is shown to the user verbatim and waited on. When the changeset touchestools/,types/,instructions/,AGENTS.mdor a<stage>/CONTRACT.md,publishprints a one-line note that CI is the last mechanical check still to come and that what follows it is covered by none. A push tomainthat movesVERSIONadditionally triggers a tagged release. CI does the tagging - a session never creates a tag, which is what keeps AGENTS.md invariant 5 intact. -
Wait for CI on the published commit, this way. One runner serves the repository and it currently runs no jobs in parallel, so the jobs of a push run one after another: CI's
verifyjob (about 8 minutes) andpwshjob (about 3 minutes) first, then the second run a push tomainstarts -release.yml, preceded by theConverterscheck - which waitsqueueduntil CI is done and then takes about 1 minute. From the push to the last green run that is about 12 minutes (measured 10.5 to 13 minutes, October 2026); a second run stillqueuedwhile CI works is the runner's order, not a hang. The times below rest on that setup (ENVIRONMENT.md§ CI records it); once the runner takes parallel jobs, measure them again and rewrite them here.- Read the runs for the published commit's SHA through the authenticated Gitea connection
ENVIRONMENT.mdlists (the Gitea MCP'sactions_run_read,list_runs), right afterpublish, to get their ids. Never anonymously viacurl: Gitea answers the Actions API with401 token is requiredeven for this public repo. - Check again after about 11 minutes, then every 2 minutes.
- Give up after 25 minutes - twice the usual time, so a slow day is not mistaken for a hang - and hand the open runs to the user by id and link, rather than waiting on.
- Count from when the runner is free, not from the push. Runs of an earlier push that are
still open when you publish run first, and the runner does not keep push order: it may take
the next push's CI before the earlier push's release run. So list the open runs right after
publish; when there are any, the first check and the give-up time start from the moment the last of them finishes. - Any shell loop that polls instead must end on the first non-2xx status or missing field and print the raw response. A loop that treats an error as "not finished yet" never ends; that happened in the #139 close-out.
- Keep the polling out of the main context where the harness allows it - a background command or a fork - so a long wait does not fill the session with run listings.
Converter changes have a second run. When the published commit touches the converter surface -
tools/chemenu/filters/,tools/chemenu/commands/raw/derive.pyoraccept.py,tools/chemenu/tests/test_raw_derive*.py,tools/chemenu/tests/binary_formats.py,tools/requirements.txtor.gitea/workflows/converters.yml- theConvertersworkflow (converters.yml) starts by itself with CI and derives the real documents of the private test corpus. Deriving the corpus takes about 10 minutes on top of CI, on the same runner and after it, so the last run finishes about 22 minutes after the push; give up after 35 minutes instead of 25, and count a red run like a red CI run (step 4). Start it by hand (actions_run_write,dispatch_workflowonmain) when only the private repository changed or when the commit reaches the converters only indirectly. A release without suffix runs the same steps as the first job ofrelease.yml, which the release waits for. - Read the runs for the published commit's SHA through the authenticated Gitea connection
-
A red run is not waited past. Read the failing job's log, fix the cause, and go back to step 1: this is still build work, whichever skill published. The phase that published ends only on a green run, and the issue stays open until there is one.