Block integration-tester contamination artifacts / Block staging-trigger / invalid manifest contamination (pull_request) Successful in 23s
Lint forbidden hand-written mcp__ tool-id literals / Scan for hand-written mcp__ tool-id literals (pull_request) Successful in 18s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 25s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 22s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 22s
Concierge Creates Workspace Hermetic / Concierge Creates Workspace Hermetic (pull_request) Successful in 36s
lint-phantom-gate / lint-phantom-gate (pull_request) Successful in 30s
lint-required-workflows-docker-host-pinned / Lint docker-host pin on docker-touching workflows (pull_request) Successful in 22s
Lint publish-runner timeout-minutes / Lint publish-runner timeout-minutes (pull_request) Successful in 29s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 37s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 1m23s
Lint schedule budget / Zero-cron ratchet (pull_request) Successful in 30s
lint-staging-tenant-cd-gate-chain / lint-staging-tenant-cd-gate-chain (pull_request) Successful in 32s
lint-setup-go-cache / lint-setup-go-cache (pull_request) Successful in 33s
lint-bp-context-emit-match / lint-bp-context-emit-match (pull_request) Successful in 1m41s
Lint workflow YAML (repository compatibility policy) / Lint workflow YAML for repository compatibility policy (pull_request) Successful in 32s
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m46s
E2E Ephemeral CP Happy Path / detect (pull_request) Successful in 1m46s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 5s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 6s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m34s
sdk-pin-drift / SDK consumer pin vs molecule-ai-sdk main (pull_request) Successful in 37s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 25s
sdk-route-milestone-contract-drift / SDK route + milestone derive-gates (pull_request) Successful in 30s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 2m21s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m42s
CI / Python Lint & Test (pull_request) Successful in 2m22s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 58s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 2m23s
ci-required-drift / drift (pull_request) Successful in 2m41s
lint-no-coe-on-required / lint-no-coe-on-required (pull_request) Successful in 2m23s
lint-context-set-shrink / lint-context-set-shrink (pull_request) Successful in 2m51s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 1m8s
pin-provenance-guard / Pin provenance (pull_request) Successful in 1m35s
E2E Chat / E2E Chat (pull_request) Successful in 3m28s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Successful in 1m12s
template-delivery-e2e / detect-changes (pull_request) Successful in 2m40s
template-delivery-e2e / Template-asset delivery (fresh seo-agent — config+prompts via asset channel, seo-all via plugin reconcile) (pull_request) Successful in 3s
lint-env-coupling-dismissal / lint-env-coupling-dismissal (pull_request) Successful in 4m42s
CI / Detect changes (pull_request) Successful in 5m30s
CI / Canvas (Next.js) (pull_request) Successful in 5m51s
CI / Canvas Deploy Status (pull_request) Successful in 1s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 6m43s
CI / Platform (Go) (pull_request) Successful in 6m49s
CI / all-required (pull_request) Successful in 30s
E2E Ephemeral CP Happy Path / E2E Ephemeral CP Happy Path (pull_request) Successful in 25m21s
gitea-merge-queue / queue (pull_request_review) Successful in 3m17s
status-reaper is LATENT, not active, and its only effect is to manufacture
a green required status. Remove it.
WHY
* It cannot currently run. Its workflow `on:` block is `workflow_dispatch:`
only -- no `schedule:`. (Verified by PyYAML parse, not grep: a synthetic
mutant with the cron restored parses as ['schedule','workflow_dispatch']
while the real file parses as ['workflow_dispatch']. Note that grepping
for `schedule:` is misleading here -- several workflows carry the string
inside comments.) Its schedule had been moved to
/etc/cron.d/molecule-core-status-reaper on the Hetzner operator host,
which was DECOMMISSIONED; that cron stanza survives only under
operator-config/archive/, whose README says archived material "is not
current operating guidance, is not installed, and must never be invoked
by a Gitea workflow". On the live k3s head there is no status-reaper
CronJob, no /etc/cron.d entry and no systemd unit, and the
/usr/local/bin/molecule-core-cron-bot.sh the comment points at does not
exist. The 5-minute compensation cadence it documents has not been
running. Repo-wide there are zero active `schedule:` triggers, enforced
by lint_schedule_budget.py's zero-cron ratchet.
* Its ONLY write manufactures green. Across all four api() call sites,
three are GET and exactly one is
POST /repos/{o}/{r}/statuses/{sha} with a hardcoded state: "success".
It does this with a CI_STATUS_TOKEN PAT rather than the Actions token,
and main branch protection is status_check_contexts: ["*"], so every
posted context must be green to merge. An uninstalled tool whose sole
effect is turning a red required context green, still dispatchable by
any maintainer, is a loaded gun in a drawer.
* Nothing depends on its compensation. Because it has not been running,
nothing currently relies on it, so removal cannot regress a green that
something needs.
* Its evidence set was incomplete by construction. It reads the combined
endpoint /commits/{sha}/status with no limit, and that endpoint silently
truncates its `statuses` array at 30 (measured on main: default 30,
page=2 returns 17 more, limit=100 returns 47). So the
`successful_contexts` set it reasoned about could never see the full
picture.
WHAT CHANGED
Deleted (all four confirmed tracked before removal, so this is not a
no-op on a nonexistent path):
.gitea/workflows/status-reaper.yml
.gitea/scripts/status-reaper.py
.gitea/scripts/tests/test_status_reaper_api.py
tests/test_status_reaper.py
No dedicated fixture directory exists (the tests build workflows in
tmp_path), and nothing imports the script as a module -- its own tests
loaded it by path via importlib. umbrella-reaper is a separate tool and
is untouched.
Eight files keep comment-only references as design/incident history;
each is annotated in place noting the tool was removed here.
NO WAIVER IS ADDED, DELIBERATELY
lint_context_set_shrink.py CHECK B exists to catch exactly this shape --
a deleted workflow whose lane silently disappears. It does not fire here,
and that was tested rather than assumed: status-reaper.yml has
fires_on_pull_request=False, so it derives no lane. Deriving the whole
tree before and after the deletion gives 46 lanes -> 46 lanes, zero lost
(positive control: deleting ci.yml loses 7). A waiver matching nothing is
a hard ERROR in that gate, so adding one "just in case" would itself red
this PR.
VERIFICATION
lint-workflow-yaml.py: 76 workflows checked, no violations.
lint_schedule_budget.py: zero-cron ratchet OK across 76 workflows.
No workflow, cron, systemd unit or CronJob can still invoke the script;
the only remaining `status-reaper` hits are prose.
Test suites, before on origin/main vs after on this branch:
.gitea/scripts/tests 38 failed / 1592 passed -> 38 failed / 1569 passed
tests/ 3 failed / 318 passed -> 3 failed / 269 passed
The failure SETS are byte-identical in both directions -- no new
failures. The pre-existing failures are Windows/docker environment
artifacts in this checkout and are unrelated to status-reaper; they are
not addressed here. The passed-count drops are exactly the 23 + 49 tests
that only tested the deleted script.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
101 lines
4.7 KiB
YAML
101 lines
4.7 KiB
YAML
name: Lint workflow YAML (repository compatibility policy)
|
|
|
|
# Tier-2 hard-gate lint (RFC internal#219 §1, charter §SOP-N rule (m)).
|
|
# Enforces repository workflow-policy shapes before they reach `main`. Rules 1
|
|
# and 2 originated under the former Gitea 1.22.6 fleet; the current server
|
|
# supports additional syntax, but policy adoption requires an explicit
|
|
# fleet/status migration rather than an incidental workflow edit.
|
|
#
|
|
# 1. workflow_dispatch.inputs — feedback_gitea_workflow_dispatch_inputs_unsupported
|
|
# (2026-05-11 PyPI freeze 24h)
|
|
# 2. on: workflow_run — not yet adopted by the status/reaper topology
|
|
# 3. name: containing "/" — breaks status-context tokenization
|
|
# 4. cross-file name collision — status-reaper rev1 fail-loud class
|
|
# (status-reaper itself was REMOVED in
|
|
# chore/delete-uninstalled-status-reaper; the
|
|
# rule it motivated still stands)
|
|
# 5. cross-repo uses: org/r/p@r — feedback_gitea_cross_repo_uses_blocked
|
|
# (DEFAULT_ACTIONS_URL=github → 404)
|
|
# 6. (WARN) api.github.com refs — feedback_act_runner_github_server_url
|
|
# without workflow-level GITHUB_SERVER_URL
|
|
#
|
|
# Empirical history this hardens against:
|
|
# - status-reaper rev1 caught rule-4 (name-collision) class
|
|
# - sop-checklist DOA'd on rule-2 (workflow_run partial)
|
|
# - #319 bootstrap-paradox (chained-defect class, related)
|
|
# - internal#329 dispatcher race (adjacent)
|
|
# - 2026-05-11 publish-runtime: rule-1, 24h PyPI freeze
|
|
#
|
|
# Triggers:
|
|
# - pull_request: pre-merge gate — block hostile shapes before they land
|
|
# - push: post-merge regression detection — catch direct-to-main edits
|
|
#
|
|
# Per RFC internal#219 §1 contract: continue-on-error: true during the
|
|
# surface-broken-shapes phase. Follow-up PR flips off after surfaced
|
|
# defects are triaged. The push-trigger ensures we catch regressions
|
|
# even if the pull_request gate is bypassed by branch-protection drift.
|
|
|
|
concurrency:
|
|
# Auto-cancel a superseded run: a newer commit/event supersedes the old
|
|
# one instead of leaving it queued forever (root fix for waiting-run pileup).
|
|
# PR events group by PR number; push events group by ref.
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: true
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- '.gitea/workflows/**'
|
|
- '.gitea/scripts/lint-workflow-yaml.py'
|
|
- 'tests/test_lint_workflow_yaml.py'
|
|
- 'tests/test_current_state_ci_docs.py'
|
|
push:
|
|
branches: [main, staging]
|
|
paths:
|
|
- '.gitea/workflows/**'
|
|
- '.gitea/scripts/lint-workflow-yaml.py'
|
|
- 'tests/test_lint_workflow_yaml.py'
|
|
- 'tests/test_current_state_ci_docs.py'
|
|
|
|
# Belt-and-suspenders against runner default
|
|
# (feedback_act_runner_github_server_url).
|
|
env:
|
|
GITHUB_SERVER_URL: https://git.moleculesai.app
|
|
|
|
jobs:
|
|
# bp-required: pending #4392
|
|
lint:
|
|
# The live wildcard branch protection already gates every posted status.
|
|
# #4392 tracks teaching Tier 2g that `*` covers this renamed context so the
|
|
# directive can become `bp-required: yes` without a redundant literal.
|
|
name: Lint workflow YAML for repository compatibility policy
|
|
runs-on: ubuntu-latest
|
|
# UNMASKED 2026-07-14 (was `continue-on-error: true`, the RFC #219 §1
|
|
# "Phase 3" mask). The old comment promised a follow-up flip "after the 4
|
|
# existing-on-main rule-2 (workflow_run) violations are migrated" — those
|
|
# migrations landed long ago; the mask outlived its reason and left this
|
|
# hard-gate lint unable to fail. It is now a real gate.
|
|
#
|
|
# Proven green before un-masking — the lint AND its unit tests, run locally
|
|
# against this tree:
|
|
# $ python3 .gitea/scripts/lint-workflow-yaml.py
|
|
# ::notice::lint-workflow-yaml: 84 workflow file(s) checked, no fatal
|
|
# repository-policy violations. (0 heuristic warning(s) emitted.) -> exit 0
|
|
# $ python3 -m pytest tests/test_lint_workflow_yaml.py -q -> all pass
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: '3.11'
|
|
|
|
- name: Install PyYAML
|
|
run: pip install --quiet 'PyYAML>=6.0'
|
|
|
|
- name: Lint .gitea/workflows/*.yml
|
|
run: python3 .gitea/scripts/lint-workflow-yaml.py
|
|
|
|
- name: Run lint-workflow-yaml unit tests
|
|
run: |
|
|
pip install --quiet pytest
|
|
python3 -m pytest tests/test_lint_workflow_yaml.py tests/test_current_state_ci_docs.py -v
|