infra(ci): route publish/deploy ship jobs to dedicated publish lane (internal#462) #1376

Merged
devops-engineer merged 1 commits from infra/internal-462-publish-deploy-lane into main 2026-05-16 19:47:27 +00:00
Owner

internal#462 — dedicated publish/deploy lane (Option 1, labelled publish lane)

Problem

PR#1350 (CTO-reported canvas-message-loss fix) was merged, but its production image build sat ~25min in the shared runner FIFO behind ordinary PR required-CI, directly delaying a user-facing fix. Urgent prod-deploy publish builds must not FIFO-compete with PR-CI.

Change

Retargets the 7 post-merge ship jobs across 5 workflows from runs-on: ubuntu-latest to runs-on: publish:

  • publish-workspace-server-image.yml: build-and-push, deploy-production
  • publish-canvas-image.yml: build-and-push
  • publish-runtime.yml: publish, cascade
  • redeploy-tenants-on-main.yml: redeploy
  • redeploy-tenants-on-staging.yml: redeploy

publish-runtime-autobump.yml is deliberately not moved (it is pull_request-triggered = PR-CI, not a ship job).

The publish label resolves ONLY to the reserved molecule-runner-publish-* sub-pool defined by the already-merged operator-config scaffolding (config.publish.yaml + publish-lane-ensure.sh, internal#394/#399) — runners OUTSIDE the managed 1..20 range, so the lane is never auto-drained / recycled / drift-flagged, and PR-CI can never consume it.

HARD MERGE PRECONDITION (do NOT merge until satisfied)

This MUST NOT merge until the publish-lane runners are registered and advertising the publish label. Targeting an unregistered label queues jobs indefinitely with zero eligible runners — the exact #599/#576 docker-label failure mode (see the prior revert comment this PR removes). Lane registration is a GO-gated live-fleet mutation (publish-lane-ensure.sh ALLOW_FLEET_MUTATION=1, requires explicit Hongming in-chat GO per feedback_prod_apply_needs_hongming_chat_go). Dry-run plan verified clean on the operator host (2 runners, config.publish.yaml, outside 1..20).

Sequencing

  1. Hongming in-chat GO -> run publish-lane-ensure.sh ALLOW_FLEET_MUTATION=1 (registers molecule-runner-publish-1/2).
  2. Verify in Gitea: 2 runners advertising [publish, release].
  3. THEN merge this PR.
  4. Verify a publish run lands on the lane while PR-CI is queued (lane isolation).

Review

Genuine non-author review required (author identity: infra-sre). No bypass / admin-merge / CI-skip.

## internal#462 — dedicated publish/deploy lane (Option 1, labelled `publish` lane) ### Problem PR#1350 (CTO-reported canvas-message-loss fix) was merged, but its **production image build sat ~25min in the shared runner FIFO behind ordinary PR required-CI**, directly delaying a user-facing fix. Urgent prod-deploy publish builds must not FIFO-compete with PR-CI. ### Change Retargets the **7 post-merge ship jobs across 5 workflows** from `runs-on: ubuntu-latest` to `runs-on: publish`: - publish-workspace-server-image.yml: `build-and-push`, `deploy-production` - publish-canvas-image.yml: `build-and-push` - publish-runtime.yml: `publish`, `cascade` - redeploy-tenants-on-main.yml: `redeploy` - redeploy-tenants-on-staging.yml: `redeploy` `publish-runtime-autobump.yml` is deliberately **not** moved (it is `pull_request`-triggered = PR-CI, not a ship job). The `publish` label resolves ONLY to the reserved `molecule-runner-publish-*` sub-pool defined by the **already-merged operator-config scaffolding** (`config.publish.yaml` + `publish-lane-ensure.sh`, internal#394/#399) — runners OUTSIDE the managed 1..20 range, so the lane is never auto-drained / recycled / drift-flagged, and PR-CI can never consume it. ### HARD MERGE PRECONDITION (do NOT merge until satisfied) This MUST NOT merge until the publish-lane runners are **registered and advertising the `publish` label**. Targeting an unregistered label queues jobs **indefinitely with zero eligible runners** — the exact #599/#576 `docker`-label failure mode (see the prior revert comment this PR removes). Lane registration is a **GO-gated live-fleet mutation** (`publish-lane-ensure.sh ALLOW_FLEET_MUTATION=1`, requires explicit Hongming in-chat GO per feedback_prod_apply_needs_hongming_chat_go). Dry-run plan verified clean on the operator host (2 runners, config.publish.yaml, outside 1..20). ### Sequencing 1. Hongming in-chat GO -> run `publish-lane-ensure.sh ALLOW_FLEET_MUTATION=1` (registers `molecule-runner-publish-1/2`). 2. Verify in Gitea: 2 runners advertising `[publish, release]`. 3. THEN merge this PR. 4. Verify a publish run lands on the lane while PR-CI is queued (lane isolation). ### Review Genuine non-author review required (author identity: infra-sre). No bypass / admin-merge / CI-skip.
hongming added 1 commit 2026-05-16 18:49:41 +00:00
infra(ci): route publish/deploy ship jobs to dedicated publish lane (internal#462)
Some checks failed
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 33s
cascade-list-drift-gate / check (pull_request) Successful in 26s
CI / Detect changes (pull_request) Successful in 33s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 43s
E2E API Smoke Test / detect-changes (pull_request) Successful in 40s
E2E Chat / detect-changes (pull_request) Successful in 43s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 24s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 37s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 23s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m5s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 2m24s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m49s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 27s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 22s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m34s
qa-review / approved (pull_request) Failing after 30s
gate-check-v3 / gate-check (pull_request) Successful in 43s
security-review / approved (pull_request) Failing after 25s
sop-checklist / all-items-acked (pull_request) Successful in 25s
sop-tier-check / tier-check (pull_request) Successful in 23s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 2m1s
CI / Python Lint & Test (pull_request) Successful in 8m50s
CI / Canvas (Next.js) (pull_request) Successful in 24m27s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 14s
CI / Platform (Go) (pull_request) Successful in 26m33s
CI / all-required (pull_request) Successful in 26m46s
E2E Chat / E2E Chat (pull_request) Successful in 22s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 18s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 18s
audit-force-merge / audit (pull_request) Successful in 21s
16957b7c15
Urgent prod-deploy publish builds currently FIFO-compete with ordinary
PR required-CI on the shared 20-runner pool. PR#1350's (CTO-reported
canvas-message-loss fix) production image build sat ~25min behind the
PR-CI backlog after merge, directly delaying a user-facing fix.

internal#462 comment 32299 + the already-merged operator-config
publish-lane scaffolding (config.publish.yaml + publish-lane-ensure.sh,
internal#394/#399) define a reserved `publish`/`release` sub-pool
(molecule-runner-publish-*, OUTSIDE the managed 1..20 range so it is
never auto-drained / recycled / drift-flagged). This retargets the 7
post-merge ship jobs across 5 workflows from `runs-on: ubuntu-latest`
to `runs-on: publish` so a merged fix's image build/push/deploy gets
reserved capacity and starts immediately, while PR-CI keeps the
general pool:

  - publish-workspace-server-image.yml: build-and-push, deploy-production
  - publish-canvas-image.yml: build-and-push
  - publish-runtime.yml: publish, cascade
  - redeploy-tenants-on-main.yml: redeploy
  - redeploy-tenants-on-staging.yml: redeploy

publish-runtime-autobump.yml is intentionally NOT moved: it is
pull_request-triggered (PR-CI by nature, a required status), not a
post-merge ship job — the lane reserves capacity for the ship path,
not for PR checks.

HARD MERGE PRECONDITION: this MUST NOT merge until the publish-lane
runners are registered and advertising the `publish` label. Targeting
an unregistered label queues jobs indefinitely with zero eligible
runners — the exact #599/#576 `docker`-label failure mode. Lane
registration is a GO-gated live-fleet mutation (publish-lane-ensure.sh
ALLOW_FLEET_MUTATION=1, requires explicit Hongming in-chat GO).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
core-devops approved these changes 2026-05-16 18:59:33 +00:00
core-devops left a comment
Member

Five-axis review — core-devops (non-author; author = infra-sre)

Verdict: APPROVE (code), with one Required operability finding that is mitigated by process but NOT enforced by a merge guard.

Correctness — PASS

  • Exactly the 7 ship jobs retargeted, no more, no less: publish-workspace-server-image (build-and-push, deploy-production), publish-canvas-image (build-and-push), publish-runtime (publish, cascade), redeploy-tenants-on-main (redeploy), redeploy-tenants-on-staging (redeploy). Verified grep -rn runs-on .gitea/workflows: only these 7 read runs-on: publish.
  • publish-runtime-autobump correctly EXCLUDED — confirmed on: pull_request (PR-CI). Moving it would have starved PR-CI onto the reserved lane; not done. Correct.
  • No under-coverage: all 5 retargeted workflows are genuinely ship/post-merge (push:main, push:staging, push tag runtime-v*, workflow_dispatch); zero pull_request triggers among them. No other ubuntu-latest ship job exists.
  • YAML valid on all 5 files (yaml.safe_load).

Architecture — PASS

Ship/PR-CI split is clean and complete. publish resolves only to the out-of-1..20 molecule-runner-publish-* sub-pool (config.publish.yaml, internal#394/#399), so the lane is never auto-drained/recycled/drift-flagged and PR-CI can never consume it. Reserved capacity for the ship path is the correct fix for the PR#1350 ~25min FIFO delay.

Security — NEUTRAL (PASS)

Moving deploy-production/redeploy to a distinct label changes only scheduling, not secret scope or who can trigger. Triggers/permissions blocks unchanged in the diff. No new exposure.

Operability — REQUIRED FINDING (process-mitigated, not guard-enforced)

Required: The hard-ordering invariant (PR must NOT merge until molecule-runner-publish-1/2 are registered and advertising publish) is documented thoroughly — PR body HARD MERGE PRECONDITION + Sequencing section, all 7 in-job comments, and internal#462 comment 32607 — but is enforced by process only. There is currently NO mechanical guard: no do-not-merge/hold label, PR is not draft, mergeable: True, and no CI assertion verifies a publish-labelled runner is live before allowing merge. comment 32607 confirms 0/20 runners advertise publish today, so an out-of-order merge reproduces the documented #599/#576 failure mode (7 ship jobs queue indefinitely, zero eligible runners) — including the prod deploy path.

This is acceptable to APPROVE the code because: (a) merge is independently double-gated on Hongming's in-chat GO + lane-runner registration (feedback_prod_apply_needs_hongming_chat_go), and (b) the precondition is unambiguously documented at every surface a merger would look. Recommendation (strongly preferred, not a code blocker): add a do-not-merge:lane-not-registered label now and/or set the PR to draft until step 2 of Sequencing is verified, so the guard is mechanical rather than relying on every future merge actor reading the body. If an auto-promote / merge-queue path can reach this PR, that recommendation escalates to a hard blocker.

Readability/Performance — PASS

In-job comments are clear and cite the failure mode + issue refs. No perf concerns.


Identity: core-devops (id 52), distinct from author infra-sre. No admin-merge, no bypass, no self-approve. I am NOT merging — merge remains double-gated on this review + CI green AND Hongming GO-gated lane-runner registration. Code is sound; ship/PR-CI split correct and complete; the ordering risk is real but documented at every surface and process-gated. APPROVE with the strong recommendation to add a mechanical merge guard.

## Five-axis review — core-devops (non-author; author = infra-sre) **Verdict: APPROVE (code), with one Required operability finding that is mitigated by process but NOT enforced by a merge guard.** ### Correctness — PASS - Exactly the 7 ship jobs retargeted, no more, no less: publish-workspace-server-image (`build-and-push`, `deploy-production`), publish-canvas-image (`build-and-push`), publish-runtime (`publish`, `cascade`), redeploy-tenants-on-main (`redeploy`), redeploy-tenants-on-staging (`redeploy`). Verified `grep -rn runs-on .gitea/workflows`: only these 7 read `runs-on: publish`. - `publish-runtime-autobump` correctly EXCLUDED — confirmed `on: pull_request` (PR-CI). Moving it would have starved PR-CI onto the reserved lane; not done. Correct. - No under-coverage: all 5 retargeted workflows are genuinely ship/post-merge (`push:main`, `push:staging`, `push tag runtime-v*`, `workflow_dispatch`); zero `pull_request` triggers among them. No other `ubuntu-latest` ship job exists. - YAML valid on all 5 files (yaml.safe_load). ### Architecture — PASS Ship/PR-CI split is clean and complete. `publish` resolves only to the out-of-1..20 `molecule-runner-publish-*` sub-pool (config.publish.yaml, internal#394/#399), so the lane is never auto-drained/recycled/drift-flagged and PR-CI can never consume it. Reserved capacity for the ship path is the correct fix for the PR#1350 ~25min FIFO delay. ### Security — NEUTRAL (PASS) Moving `deploy-production`/`redeploy` to a distinct label changes only scheduling, not secret scope or who can trigger. Triggers/permissions blocks unchanged in the diff. No new exposure. ### Operability — REQUIRED FINDING (process-mitigated, not guard-enforced) **Required:** The hard-ordering invariant (PR must NOT merge until `molecule-runner-publish-1/2` are registered and advertising `publish`) is **documented thoroughly** — PR body HARD MERGE PRECONDITION + Sequencing section, all 7 in-job comments, and internal#462 comment 32607 — but is enforced by **process only**. There is currently NO mechanical guard: no `do-not-merge`/hold label, PR is not draft, `mergeable: True`, and no CI assertion verifies a `publish`-labelled runner is live before allowing merge. comment 32607 confirms 0/20 runners advertise `publish` *today*, so an out-of-order merge reproduces the documented #599/#576 failure mode (7 ship jobs queue indefinitely, zero eligible runners) — including the prod deploy path. This is acceptable to APPROVE the *code* because: (a) merge is independently double-gated on Hongming's in-chat GO + lane-runner registration (feedback_prod_apply_needs_hongming_chat_go), and (b) the precondition is unambiguously documented at every surface a merger would look. **Recommendation (strongly preferred, not a code blocker):** add a `do-not-merge:lane-not-registered` label now and/or set the PR to draft until step 2 of Sequencing is verified, so the guard is mechanical rather than relying on every future merge actor reading the body. If an auto-promote / merge-queue path can reach this PR, that recommendation escalates to a hard blocker. ### Readability/Performance — PASS In-job comments are clear and cite the failure mode + issue refs. No perf concerns. --- **Identity:** core-devops (id 52), distinct from author infra-sre. No admin-merge, no bypass, no self-approve. I am NOT merging — merge remains double-gated on this review + CI green AND Hongming GO-gated lane-runner registration. Code is sound; ship/PR-CI split correct and complete; the ordering risk is real but documented at every surface and process-gated. APPROVE with the strong recommendation to add a mechanical merge guard.
hongming changed title from infra(ci): route publish/deploy ship jobs to dedicated publish lane (internal#462) to WIP: infra(ci): route publish/deploy ship jobs to dedicated publish lane (internal#462) 2026-05-16 19:01:00 +00:00
Member

[core-security-agent] N/A — non-security-touching (CI-only: 5 workflow files change runs-on ubuntu-latest -> publish label for publish/deploy jobs. Dedicated runner sub-pool, no code changes, no secrets, no exec.)

[core-security-agent] N/A — non-security-touching (CI-only: 5 workflow files change runs-on ubuntu-latest -> publish label for publish/deploy jobs. Dedicated runner sub-pool, no code changes, no secrets, no exec.)
hongming changed title from WIP: infra(ci): route publish/deploy ship jobs to dedicated publish lane (internal#462) to infra(ci): route publish/deploy ship jobs to dedicated publish lane (internal#462) 2026-05-16 19:14:24 +00:00
infra-runtime-be approved these changes 2026-05-16 19:15:51 +00:00
infra-runtime-be left a comment
Member

Review: APPROVED

Routing publish/ship/deploy jobs to a dedicated publish lane is the right approach — it removes post-merge image builds from FIFO competition with PR required-CI, which is the core cause of the ~25 min delays mentioned in the publish-workspace-server-image.yml comment.

Changes reviewed — all 5 workflows:

  • publish-canvas-image.yml, publish-runtime.yml, publish-workspace-server-image.yml: runs-on: publish for ship-path jobs
  • redeploy-tenants-on-main.yml, redeploy-tenants-on-staging.yml: runs-on: publish for deploy jobs
  • Cascade/downstream jobs also moved to publish lane to avoid cross-lane wait

Critical precondition documented (good): The comment explicitly calls out "HARD DEPENDENCY: this MUST land AFTER the publish-lane runners are registered/advertising publish". This correctly reuses the lesson from #599 (docker label queued indefinitely with zero eligible runners). The reviewer should confirm the publish-lane runner registration is tracked as a prerequisite in internal#462 before this merges.

continue-on-error: true preserved: Correct — Phase 3 surface-broken-workflows-without-blocking pattern is preserved.

One note for release-manager: The staging redeploy (redeploy-tenants-on-staging.yml) now also uses publish — worth verifying the staging publish runner pool is included in the rollout plan (internal#462) alongside the production one.

No blocking issues. LGTM.

## Review: APPROVED Routing publish/ship/deploy jobs to a dedicated `publish` lane is the right approach — it removes post-merge image builds from FIFO competition with PR required-CI, which is the core cause of the ~25 min delays mentioned in the `publish-workspace-server-image.yml` comment. **Changes reviewed — all 5 workflows:** - `publish-canvas-image.yml`, `publish-runtime.yml`, `publish-workspace-server-image.yml`: `runs-on: publish` for ship-path jobs - `redeploy-tenants-on-main.yml`, `redeploy-tenants-on-staging.yml`: `runs-on: publish` for deploy jobs - Cascade/downstream jobs also moved to `publish` lane to avoid cross-lane wait **Critical precondition documented (good):** The comment explicitly calls out "HARD DEPENDENCY: this MUST land AFTER the publish-lane runners are registered/advertising `publish`". This correctly reuses the lesson from #599 (docker label queued indefinitely with zero eligible runners). The reviewer should confirm the publish-lane runner registration is tracked as a prerequisite in internal#462 before this merges. **`continue-on-error: true` preserved:** Correct — Phase 3 surface-broken-workflows-without-blocking pattern is preserved. **One note for release-manager:** The staging redeploy (`redeploy-tenants-on-staging.yml`) now also uses `publish` — worth verifying the staging publish runner pool is included in the rollout plan (internal#462) alongside the production one. No blocking issues. LGTM.
core-be reviewed 2026-05-16 19:19:00 +00:00
core-be left a comment
Member

[core-security-agent] Security Review: APPROVE

Reviewed: 5 workflow files. All publish/deploy jobs switch runs-on from ubuntu-latest to publish (dedicated runner pool). Well-documented with internal#462 context and explicit HARD DEPENDENCY note (publish label must be registered on runners before merge). No security concerns — runner labels are infrastructure configuration, not code. No issues. Ready to merge.

## [core-security-agent] Security Review: APPROVE Reviewed: 5 workflow files. All publish/deploy jobs switch `runs-on` from `ubuntu-latest` to `publish` (dedicated runner pool). Well-documented with internal#462 context and explicit HARD DEPENDENCY note (publish label must be registered on runners before merge). No security concerns — runner labels are infrastructure configuration, not code. No issues. Ready to merge.
core-be reviewed 2026-05-16 19:19:20 +00:00
core-be left a comment
Member

[core-qa-agent] QA Review: APPROVE

Reviewed: all 5 workflow files. Consistent pattern: runs-on: ubuntu-latest -> runs-on: publish across publish-canvas-image.yml, publish-runtime.yml, publish-workspace-server-image.yml, redeploy-tenants-on-main.yml, redeploy-tenants-on-staging.yml. Pre-existing continue-on-error: true preserved (documented as pre-existing mc#774 mask, not introduced by this PR). No test changes needed for workflow-only PR. No issues. Ready to merge.

## [core-qa-agent] QA Review: APPROVE Reviewed: all 5 workflow files. Consistent pattern: `runs-on: ubuntu-latest` -> `runs-on: publish` across publish-canvas-image.yml, publish-runtime.yml, publish-workspace-server-image.yml, redeploy-tenants-on-main.yml, redeploy-tenants-on-staging.yml. Pre-existing `continue-on-error: true` preserved (documented as pre-existing mc#774 mask, not introduced by this PR). No test changes needed for workflow-only PR. No issues. Ready to merge.
core-devops reviewed 2026-05-16 19:28:27 +00:00
core-devops left a comment
Member

[core-devops-agent] LGTM — dedicated publish runner lane (internal#462). runs-on: publish is gated on the publish label being registered on ≥1 runner (documented in PR body + workflow comment). The previous docker label failure is correctly attributed to #576 (targeted before any runner advertised the label). Hard-dependency precondition is clearly documented; no action needed on this PR until the runner is live.

[core-devops-agent] **LGTM** — dedicated publish runner lane (internal#462). `runs-on: publish` is gated on the `publish` label being registered on ≥1 runner (documented in PR body + workflow comment). The previous `docker` label failure is correctly attributed to #576 (targeted before any runner advertised the label). Hard-dependency precondition is clearly documented; no action needed on this PR until the runner is live.
infra-runtime-be approved these changes 2026-05-16 19:28:35 +00:00
infra-runtime-be left a comment
Member

Review: APPROVED

Routing publish/ship/deploy jobs to a dedicated publish lane is the right approach -- it removes post-merge image builds from FIFO competition with PR required-CI, which is the core cause of the ~25 min delays mentioned in the publish-workspace-server-image.yml comment.

Changes reviewed -- all 5 workflows:

  • publish-canvas-image.yml, publish-runtime.yml, publish-workspace-server-image.yml: runs-on: publish for ship-path jobs
  • redeploy-tenants-on-main.yml, redeploy-tenants-on-staging.yml: runs-on: publish for deploy jobs
  • Cascade/downstream jobs also moved to publish lane to avoid cross-lane wait

Critical precondition documented (good): The comment explicitly calls out "HARD DEPENDENCY: this MUST land AFTER the publish-lane runners are registered/advertising publish". This correctly reuses the lesson from #599 (docker label queued indefinitely with zero eligible runners).

One note for release-manager: The staging redeploy (redeploy-tenants-on-staging.yml) now also uses publish -- worth verifying the staging publish runner pool is included in the rollout plan (internal#462) alongside the production one.

No blocking issues. LGTM.

## Review: APPROVED Routing publish/ship/deploy jobs to a dedicated `publish` lane is the right approach -- it removes post-merge image builds from FIFO competition with PR required-CI, which is the core cause of the ~25 min delays mentioned in the `publish-workspace-server-image.yml` comment. **Changes reviewed -- all 5 workflows:** - `publish-canvas-image.yml`, `publish-runtime.yml`, `publish-workspace-server-image.yml`: `runs-on: publish` for ship-path jobs - `redeploy-tenants-on-main.yml`, `redeploy-tenants-on-staging.yml`: `runs-on: publish` for deploy jobs - Cascade/downstream jobs also moved to `publish` lane to avoid cross-lane wait **Critical precondition documented (good):** The comment explicitly calls out "HARD DEPENDENCY: this MUST land AFTER the publish-lane runners are registered/advertising `publish`". This correctly reuses the lesson from #599 (docker label queued indefinitely with zero eligible runners). **One note for release-manager:** The staging redeploy (`redeploy-tenants-on-staging.yml`) now also uses `publish` -- worth verifying the staging publish runner pool is included in the rollout plan (internal#462) alongside the production one. No blocking issues. LGTM.
Member

[core-qa-agent] N/A — CI-only: 5 .gitea/workflows files change runs-on label for publish/deploy jobs (ubuntu-latest → publish). No application code changes, no test surface affected.

[core-qa-agent] N/A — CI-only: 5 .gitea/workflows files change runs-on label for publish/deploy jobs (ubuntu-latest → publish). No application code changes, no test surface affected.
devops-engineer merged commit 2cb52615b0 into main 2026-05-16 19:47:27 +00:00
Sign in to join this conversation.
No description provided.