Skip to content

ci: port the workflows to .forgejo/, and correct the context-format finding - #527

Merged
ProtocolWarden merged 1 commit into
mainfrom
ci/port-workflows-to-forgejo
Aug 19, 2026
Merged

ci: port the workflows to .forgejo/, and correct the context-format finding#527
ProtocolWarden merged 1 commit into
mainfrom
ci/port-workflows-to-forgejo

Conversation

@ProtocolWarden

Copy link
Copy Markdown
Owner

Two things, both from running Forgejo Actions rather than reasoning about it.

First, a correction to #526

#526 claimed run-name: pins the middle segment of Forgejo's status context. That is wrong. A two-job workflow with run-name: probe produces:

multi / alpha (pull_request)
multi / beta  (pull_request)

probe appears in neither. A job carrying name: Pretty Job Name produces naming / Pretty Job Name (pull_request). So the format is:

<workflow name:> / <job name:, or the job id> (<event>)

…and it is stable by default — no run-name: needed, and each job gets its own context exactly as on GitHub, just prefixed by the workflow name.

The commit-message form I first observed (audit.yml / ci: probe the status context name (push)) appears only when a run fails before any job starts — with no job to name, Forgejo falls back to the file name and run title. I generalised a fallback into a rule.

Second, the port

Forgejo executes .github/workflows/ as well as .forgejo/. Pushing OC to the instance handed a single local runner the entire GitHub CI suite — 27 tasks dispatched, most failing, the audit stuck behind them.

All three workflows are ported to .forgejo/workflows/ with their jobs byte-identical (verified by parsing both files and comparing the jobs mappings), and one deliberate change: on: is pull_request only, because a push trigger produces a second, separate context on the same head.

The 13 contexts these produce

CI / Lint (ruff) (pull_request)
CI / Type check (ty) (pull_request)
CI / Custodian doctor (pull_request)
CI / License headers (pull_request)
CI / Test (pytest) (pull_request)
CI / Reviewer state-machine tests (pull_request)
CI / Reviewer integration tests (pull_request)
CI / Test (suites outside tests/unit) (pull_request)
CI / Performance regression tests (pull_request)
CI / Snapshot validation (pull_request)
CI / Flaky test detection (pull_request)
custodian-audit / audit (pull_request)
EVAL corpus integrity / EVAL corpus integrity (pull_request)

These are what Forgejo branch protection must require.

Why this is additive

Deleting .github/workflows/ cannot merge here. It removes the audit status branch protection requires, with enforce_admins on — so that PR could never go green, by construction. The deletion lands on Forgejo after the fleet cuts over.

GitHub CI is untouched and still gates this PR.

🤖 Generated with Claude Code

…inding

Two things, both from running Forgejo Actions rather than reasoning about it.

FIRST, A CORRECTION. #526 claimed `run-name:` pins the middle segment of
Forgejo's status context. That is wrong. A two-job workflow with
`run-name: probe` produces:

    multi / alpha (pull_request)
    multi / beta  (pull_request)

`probe` appears in neither. A job carrying `name: Pretty Job Name` produces
`naming / Pretty Job Name (pull_request)`. So the format is

    <workflow name:> / <job name:, or the job id> (<event>)

and it is STABLE BY DEFAULT — no `run-name:` required, and each job gets its
own context exactly as on GitHub, just prefixed. The commit-message form I
first observed appears only when a run fails before any job starts, where
Forgejo falls back to the file name and run title. I generalised a fallback
into a rule.

SECOND, THE PORT. Forgejo executes `.github/workflows/` as well as `.forgejo/`,
so pushing OC to the instance handed a single local runner the whole GitHub CI
suite — 27 tasks dispatched, most failing, the audit queued behind them. The
three workflows are now ported to `.forgejo/workflows/` with their jobs
byte-identical (verified by parsing both and comparing the `jobs` mappings) and
one deliberate change: `on:` is pull_request only, because a `push` trigger
produces a second, separate context on the same head.

The 13 contexts these produce are enumerated in the spec, and are what Forgejo
branch protection must require.

This change is ADDITIVE on purpose. Deleting `.github/workflows/` cannot merge
here: it removes the `audit` status branch protection requires, with
enforce_admins on, so that PR could never go green. The deletion lands on
Forgejo after the fleet cuts over.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ProtocolWarden

ProtocolWarden commented Aug 19, 2026

Copy link
Copy Markdown
Owner Author

Resolved: PR merged

Self-review concerns — auto-fixing (up to 6 attempts; re-queued if still unresolved):

Failed checks: code_quality

@ProtocolWarden
ProtocolWarden merged commit 9ec7e5b into main Aug 19, 2026
27 checks passed
@ProtocolWarden
ProtocolWarden deleted the ci/port-workflows-to-forgejo branch August 19, 2026 22:19
ProtocolWarden added a commit that referenced this pull request Aug 21, 2026
…le backlog items

half that is genuinely cosmetic and leaves the half that is not.

Renames (each had exactly one importer or none, no behavior change):

* `propagation/plane_adapter.py` -> `board_adapter.py`, `PlaneTaskCreator` ->
  `BoardTaskCreator`. Docstrings in `propagator.py` still pointed at
  `PlaneClient.create_issue`, a class deleted in #521.
* `tests/test_plane_parsing.py` -> `test_task_parsing.py` — it tests
  `TaskParser` and never touched Plane.
* `docs/design/plane_kodo_wrapper.md` -> `docs/history/plane-kodo-wrapper.md`,
  `status: implemented` -> `superseded`. It sat among live design docs
  describing a retired board AND a retired engine.

And one that was not cosmetic. `config/plane_task_template.example.md` was a
stale copy of `render_task_template()` output (it still said "the change you
want Kodo to make"). No code read it — `oc setup` writes
`config/task_template.local.md`. But `.gitignore`, `docs/operator/setup.md` and
BOTH secrets scripts still named the dead `plane_task_template.local.md` path,
so `backup-secrets.sh` was backing up a file that cannot exist and the
operator's real template was in no backup at all. All four repointed; the stale
example deleted. Also dropped `.gitignore` entries for `deployment/plane/**`
and `tools/report/kodo_plane/` — no such directories.

Left alone on purpose: `plane_task_id` (read from on-disk review state),
`plane_issue_id` (read from proposer artifacts), and `"plane"` as an alert
channel name (validated against operator config). Those are wire formats; a
bare rename orphans in-flight reviews. Filed in Up Next as a write-both
migration.

Both Up Next items were already done and just unrecorded — moved to Done with
evidence: the ~1,830-test CI gap is covered by the `test-rest` job
(`pytest tests/ --ignore=tests/unit`, #525, survived the #527 port), and
`audit` on Forgejo Actions is live (runner registered, workflow ported to
`.forgejo/workflows/custodian-audit.yml`, branch protection requiring
`custodian-audit / audit (pull_request)` with apply_to_admins).

Verified with imports forced to the worktree (PYTHONPATH), not the live
checkout the fleet runs from: 67 targeted tests pass, ruff check and
format clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ProtocolWarden added a commit that referenced this pull request Aug 21, 2026
…le backlog items

half that is genuinely cosmetic and leaves the half that is not.

Renames (each had exactly one importer or none, no behavior change):

* `propagation/plane_adapter.py` -> `board_adapter.py`, `PlaneTaskCreator` ->
  `BoardTaskCreator`. Docstrings in `propagator.py` still pointed at
  `PlaneClient.create_issue`, a class deleted in #521.
* `tests/test_plane_parsing.py` -> `test_task_parsing.py` — it tests
  `TaskParser` and never touched Plane.
* `docs/design/plane_kodo_wrapper.md` -> `docs/history/plane-kodo-wrapper.md`,
  `status: implemented` -> `superseded`. It sat among live design docs
  describing a retired board AND a retired engine.

And one that was not cosmetic. `config/plane_task_template.example.md` was a
stale copy of `render_task_template()` output (it still said "the change you
want Kodo to make"). No code read it — `oc setup` writes
`config/task_template.local.md`. But `.gitignore`, `docs/operator/setup.md` and
BOTH secrets scripts still named the dead `plane_task_template.local.md` path,
so `backup-secrets.sh` was backing up a file that cannot exist and the
operator's real template was in no backup at all. All four repointed; the stale
example deleted. Also dropped `.gitignore` entries for `deployment/plane/**`
and `tools/report/kodo_plane/` — no such directories.

Left alone on purpose: `plane_task_id` (read from on-disk review state),
`plane_issue_id` (read from proposer artifacts), and `"plane"` as an alert
channel name (validated against operator config). Those are wire formats; a
bare rename orphans in-flight reviews. Filed in Up Next as a write-both
migration.

Both Up Next items were already done and just unrecorded — moved to Done with
evidence: the ~1,830-test CI gap is covered by the `test-rest` job
(`pytest tests/ --ignore=tests/unit`, #525, survived the #527 port), and
`audit` on Forgejo Actions is live (runner registered, workflow ported to
`.forgejo/workflows/custodian-audit.yml`, branch protection requiring
`custodian-audit / audit (pull_request)` with apply_to_admins).

Verified with imports forced to the worktree (PYTHONPATH), not the live
checkout the fleet runs from: 67 targeted tests pass, ruff check and
format clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ProtocolWarden added a commit that referenced this pull request Aug 21, 2026
…le backlog items (#529)

half that is genuinely cosmetic and leaves the half that is not.

Renames (each had exactly one importer or none, no behavior change):

* `propagation/plane_adapter.py` -> `board_adapter.py`, `PlaneTaskCreator` ->
  `BoardTaskCreator`. Docstrings in `propagator.py` still pointed at
  `PlaneClient.create_issue`, a class deleted in #521.
* `tests/test_plane_parsing.py` -> `test_task_parsing.py` — it tests
  `TaskParser` and never touched Plane.
* `docs/design/plane_kodo_wrapper.md` -> `docs/history/plane-kodo-wrapper.md`,
  `status: implemented` -> `superseded`. It sat among live design docs
  describing a retired board AND a retired engine.

And one that was not cosmetic. `config/plane_task_template.example.md` was a
stale copy of `render_task_template()` output (it still said "the change you
want Kodo to make"). No code read it — `oc setup` writes
`config/task_template.local.md`. But `.gitignore`, `docs/operator/setup.md` and
BOTH secrets scripts still named the dead `plane_task_template.local.md` path,
so `backup-secrets.sh` was backing up a file that cannot exist and the
operator's real template was in no backup at all. All four repointed; the stale
example deleted. Also dropped `.gitignore` entries for `deployment/plane/**`
and `tools/report/kodo_plane/` — no such directories.

Left alone on purpose: `plane_task_id` (read from on-disk review state),
`plane_issue_id` (read from proposer artifacts), and `"plane"` as an alert
channel name (validated against operator config). Those are wire formats; a
bare rename orphans in-flight reviews. Filed in Up Next as a write-both
migration.

Both Up Next items were already done and just unrecorded — moved to Done with
evidence: the ~1,830-test CI gap is covered by the `test-rest` job
(`pytest tests/ --ignore=tests/unit`, #525, survived the #527 port), and
`audit` on Forgejo Actions is live (runner registered, workflow ported to
`.forgejo/workflows/custodian-audit.yml`, branch protection requiring
`custodian-audit / audit (pull_request)` with apply_to_admins).

Verified with imports forced to the worktree (PYTHONPATH), not the live
checkout the fleet runs from: 67 targeted tests pass, ruff check and
format clean.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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