CI: github.event.schedule is empty on this Forgejo, so every cron-gated job — including tier-1 corpus — skipped on all 36 scheduled runs #109

Closed
opened 2026-09-04 15:19:33 +02:00 by buildagent · 3 comments
Member

Verified first-hand against the Forgejo API, not inferred from config.

The measurement

.forgejo/workflows/ci.yml:206-209 declares two schedules:

  schedule:
    - cron: "0 3 * * *"     # nightly
    - cron: "0 4 * * 0"     # Sunday: tier-3 corpus-scale

Across the repository's entire run history:

total_count: 574
events: push 539 | pull_request 10 | workflow_dispatch 25 | schedule 0

(The 25 rows the API returns with an empty event all carry trigger_event: workflow_dispatch.) GET /actions/runs?event=schedule returns "No workflow runs found".

Neither cron has ever fired, once, since the repository existed.

What that actually costs

Three jobs are gated on the schedule expression and therefore run only when a human dispatches them by hand:

job if: consequence
corpus-scale (OSS corpus tier-3 scale, weekly) workflow_dispatch || (schedule && cron == '0 4 * * 0') the tier-3 scale leg, and the 900s wall-clock ceiling that is described in this file as "the only gate that ever went red"
plugin-path-cost (plugin path cost + pool throughput, weekly) same shape the plugin-path cost measurement
grammar-rebuild (grammar rebuild from source, weekly) same shape reproducibility of the checked-in grammars

This is worse than a missing gate, because the project has an explicit, hard-won finding that correctness gates cannot see slowdowns: a 3.2× cold-index regression passed ~1950 tests and CI 10/10 three times, and only a weekly wall-clock ceiling caught it. That ceiling is in corpus-scale. It has never run on its own schedule. Every time it did catch something, someone had dispatched it manually — which means the safety net is a habit, not a gate.

The tier-1 corpus job is fine and should not be confused with these: its condition is github.event_name != 'schedule' || github.event.schedule == '0 3 * * *', so it runs on every push. Run 573 confirms OSS corpus (tier 1) | success alongside ... (weekly) | skipped for the other three. The nightly leg adds nothing it does not already get from pushes.

So the precise damage is: the three weekly jobs are manual-only, and nothing says so.

Why it was invisible

Every one of these jobs reports skipped on a push run, which is correct and expected behaviour for a cron-gated job — it looks exactly the same whether the cron works or not. There is no surface anywhere that says "this job last ran 12 days ago" or "this schedule has never fired". A job that never runs and a job that is correctly skipped are indistinguishable in the run list.

Same shape as the two findings filed today next to it: a check that is green while the thing it checks is false.

What to investigate

  1. Does this Forgejo instance evaluate schedule at all? Forgejo only schedules workflows found on the repository's default branch, and support/behaviour has moved across versions. That is the first thing to establish, because if the answer is no, every fix below is cosmetic.
  2. If schedules do work here, why is this repo's not registered — was ci.yml gaining its schedule: block after the last default-branch evaluation, does it need a push to master to (re-)register, or is it a runner-label / repo-setting problem?
  3. A push can land with zero runs dispatched on this instance — that has already happened here once, with 55 commits, because the push.branches list did not match. So "the config looks right" is not evidence; only a dispatched run is.

The fix, whatever the cause

  • If cron works: prove it with an actual scheduled run, and record the run number here. A CI job is verified by dispatching it — reproducing its payload locally proves the payload, not the job.
  • If cron does not work on this instance: stop pretending. Either move the three jobs onto a trigger that does fire, or state in the workflow that they are manual-only and add them to the release checklist — a ceiling nobody runs is not a ceiling.
  • Either way, the run-history check above is cheap and should be part of whatever periodically audits CI: event=schedule returning zero is a one-line probe.

Aside, same file

ci.yml's header comment says the corpus gate is "seven real repositories pinned by sha in tests/corpus/corpus.toml". corpus.toml pins nine (rust-ripgrep, python-flask, ts-zod, js-express, php-guzzle, ruby-sinatra, cs-dapper, rust-analyzer, py-django). Harmless drift, worth correcting while the file is open.

Filed alongside #108 (COSI_CORPUS_REQUIRE=1 has a floor of one, not of nine). The two compound: a corpus gate that can silently shrink to one repo, carried partly by a leg that never fires.

Verified first-hand against the Forgejo API, not inferred from config. ## The measurement `.forgejo/workflows/ci.yml:206-209` declares two schedules: ```yaml schedule: - cron: "0 3 * * *" # nightly - cron: "0 4 * * 0" # Sunday: tier-3 corpus-scale ``` Across the repository's entire run history: ``` total_count: 574 events: push 539 | pull_request 10 | workflow_dispatch 25 | schedule 0 ``` (The 25 rows the API returns with an empty `event` all carry `trigger_event: workflow_dispatch`.) `GET /actions/runs?event=schedule` returns **"No workflow runs found"**. **Neither cron has ever fired, once, since the repository existed.** ## What that actually costs Three jobs are gated on the schedule expression and therefore run **only when a human dispatches them by hand**: | job | `if:` | consequence | |---|---|---| | `corpus-scale` (OSS corpus tier-3 scale, weekly) | `workflow_dispatch \|\| (schedule && cron == '0 4 * * 0')` | the tier-3 scale leg, and the **900s wall-clock ceiling** that is described in this file as "the only gate that ever went red" | | `plugin-path-cost` (plugin path cost + pool throughput, weekly) | same shape | the plugin-path cost measurement | | `grammar-rebuild` (grammar rebuild from source, weekly) | same shape | reproducibility of the checked-in grammars | This is worse than a missing gate, because the project has an explicit, hard-won finding that **correctness gates cannot see slowdowns**: a 3.2× cold-index regression passed ~1950 tests and CI 10/10 three times, and *only a weekly wall-clock ceiling caught it*. That ceiling is in `corpus-scale`. It has never run on its own schedule. Every time it did catch something, someone had dispatched it manually — which means the safety net is a habit, not a gate. **The tier-1 `corpus` job is fine** and should not be confused with these: its condition is `github.event_name != 'schedule' || github.event.schedule == '0 3 * * *'`, so it runs on every push. Run 573 confirms `OSS corpus (tier 1) | success` alongside `... (weekly) | skipped` for the other three. The nightly leg adds nothing it does not already get from pushes. So the precise damage is: **the three weekly jobs are manual-only, and nothing says so.** ## Why it was invisible Every one of these jobs reports `skipped` on a push run, which is correct and expected behaviour for a cron-gated job — it looks exactly the same whether the cron works or not. There is no surface anywhere that says "this job last ran 12 days ago" or "this schedule has never fired". A job that never runs and a job that is correctly skipped are indistinguishable in the run list. Same shape as the two findings filed today next to it: a check that is green while the thing it checks is false. ## What to investigate 1. **Does this Forgejo instance evaluate `schedule` at all?** Forgejo only schedules workflows found on the repository's **default branch**, and support/behaviour has moved across versions. That is the first thing to establish, because if the answer is no, every fix below is cosmetic. 2. If schedules do work here, why is this repo's not registered — was `ci.yml` gaining its `schedule:` block after the last default-branch evaluation, does it need a push to master to (re-)register, or is it a runner-label / repo-setting problem? 3. **A push can land with zero runs dispatched on this instance** — that has already happened here once, with 55 commits, because the `push.branches` list did not match. So "the config looks right" is not evidence; only a dispatched run is. ## The fix, whatever the cause - If cron works: prove it with an actual scheduled run, and record the run number here. **A CI job is verified by dispatching it** — reproducing its payload locally proves the payload, not the job. - If cron does not work on this instance: stop pretending. Either move the three jobs onto a trigger that does fire, or state in the workflow that they are manual-only and add them to the release checklist — a ceiling nobody runs is not a ceiling. - Either way, the run-history check above is cheap and should be part of whatever periodically audits CI: `event=schedule` returning zero is a one-line probe. ## Aside, same file `ci.yml`'s header comment says the corpus gate is *"seven real repositories pinned by sha in tests/corpus/corpus.toml"*. `corpus.toml` pins **nine** (`rust-ripgrep`, `python-flask`, `ts-zod`, `js-express`, `php-guzzle`, `ruby-sinatra`, `cs-dapper`, `rust-analyzer`, `py-django`). Harmless drift, worth correcting while the file is open. ## Related Filed alongside #108 (`COSI_CORPUS_REQUIRE=1` has a floor of one, not of nine). The two compound: a corpus gate that can silently shrink to one repo, carried partly by a leg that never fires.
Author
Member

Correction: the title and the diagnosis in the body are WRONG. The crons DO fire.

Re-measured across all 575 runs, counting both the event field and trigger_event:

('push',           'push')              503
('push',           'schedule')           36   <-- the crons fire
('<blank>',  'workflow_dispatch')        26
('pull_request',   'pull_request')       10

36 ci.yml runs carry trigger_event: schedule, and every one of them succeeded.

My original measurement queried ?event=schedule and read "No workflow runs found" as proof. It was not a measurement: Forgejo records scheduled runs with event: push, and puts the real trigger in trigger_event. The filter I used could not return a scheduled run no matter how many existed. That is the same vacuous-verification failure this repo has been bitten by before — a check that was green while the thing it checked was false — committed here in the act of reporting one.

What is actually broken

The scheduler works. The discriminator does not.

Because Forgejo sets event: push on a scheduled run, github.event_name is never 'schedule' and github.event.schedule is empty. So every cron-discriminating condition in ci.yml evaluates the same way on a scheduled run as on a push:

job condition on a scheduled run
corpus (tier 1) github.event_name != 'schedule' || … 'push' != 'schedule' → true → runs
corpus-scale … == 'workflow_dispatch' || (… == 'schedule' && github.event.schedule == '0 4 * * 0') false → skipped
plugin-path-cost same shape false → skipped
grammar-rebuild same shape false → skipped

So the consequence in the original report survives intact — corpus-scale, plugin-path-cost and grammar-rebuild have never run except by hand, and with them the 900s wall-clock ceiling that is the only gate that ever caught the 3.2× cold-index regression. But the cause is a broken conditional, not a dead scheduler, and the fix is much cheaper than anything the original body proposed.

Revised direction

Do not move these jobs onto the release gate — that suggestion was contingent on cron being dead, and it is not. A working weekly cadence is what they were designed for.

The workflow needs a split its two crons can actually express. Worth weighing, and the second is the one I would look at first:

  1. discriminate on something that exists on this instance rather than on github.event_name;
  2. put the two crons in separate workflow files, so each cron's jobs need no discrimination at all — removing the need for a discriminator rather than finding a better one.

The reusable lesson, which is the real yield

Three separate things had to line up for this to stay invisible for the repository's whole history:

  1. a cron-gated job reports skipped on a push run, which is correct behaviour and looks identical to a job whose condition can never be true;
  2. the scheduled runs themselves are green, so the run list looks healthy;
  3. the obvious probe (?event=schedule) returns zero for a reason that has nothing to do with whether cron works.

Any future check must count trigger_event, not event — and must assert that the jobs ran, not that the run happened. A scheduled run in which every scheduled job skips is exactly what this repo has had 36 times.

Retitling is warranted; the issue stands, with a smaller and better-understood fix.

## Correction: the title and the diagnosis in the body are WRONG. The crons DO fire. Re-measured across all 575 runs, counting **both** the `event` field and `trigger_event`: ``` ('push', 'push') 503 ('push', 'schedule') 36 <-- the crons fire ('<blank>', 'workflow_dispatch') 26 ('pull_request', 'pull_request') 10 ``` **36 `ci.yml` runs carry `trigger_event: schedule`, and every one of them succeeded.** My original measurement queried `?event=schedule` and read "No workflow runs found" as proof. It was not a measurement: **Forgejo records scheduled runs with `event: push`**, and puts the real trigger in `trigger_event`. The filter I used could not return a scheduled run no matter how many existed. That is the same vacuous-verification failure this repo has been bitten by before — a check that was green while the thing it checked was false — committed here in the act of reporting one. ## What is actually broken The scheduler works. The **discriminator** does not. Because Forgejo sets `event: push` on a scheduled run, `github.event_name` is never `'schedule'` and `github.event.schedule` is empty. So every cron-discriminating condition in `ci.yml` evaluates the same way on a scheduled run as on a push: | job | condition | on a scheduled run | |---|---|---| | `corpus` (tier 1) | `github.event_name != 'schedule' \|\| …` | `'push' != 'schedule'` → **true → runs** | | `corpus-scale` | `… == 'workflow_dispatch' \|\| (… == 'schedule' && github.event.schedule == '0 4 * * 0')` | **false → skipped** | | `plugin-path-cost` | same shape | **false → skipped** | | `grammar-rebuild` | same shape | **false → skipped** | So the *consequence* in the original report survives intact — **`corpus-scale`, `plugin-path-cost` and `grammar-rebuild` have never run except by hand**, and with them the 900s wall-clock ceiling that is the only gate that ever caught the 3.2× cold-index regression. But the cause is a broken conditional, not a dead scheduler, and the fix is much cheaper than anything the original body proposed. ## Revised direction Do **not** move these jobs onto the release gate — that suggestion was contingent on cron being dead, and it is not. A working weekly cadence is what they were designed for. The workflow needs a split its two crons can actually express. Worth weighing, and the second is the one I would look at first: 1. discriminate on something that exists on this instance rather than on `github.event_name`; 2. **put the two crons in separate workflow files**, so each cron's jobs need no discrimination at all — removing the need for a discriminator rather than finding a better one. ## The reusable lesson, which is the real yield Three separate things had to line up for this to stay invisible for the repository's whole history: 1. a cron-gated job reports `skipped` on a push run, which is **correct behaviour** and looks identical to a job whose condition can never be true; 2. the scheduled runs themselves are **green**, so the run list looks healthy; 3. the obvious probe (`?event=schedule`) returns zero for a reason that has nothing to do with whether cron works. Any future check must count `trigger_event`, not `event` — and must assert that the *jobs* ran, not that the *run* happened. A scheduled run in which every scheduled job skips is exactly what this repo has had 36 times. Retitling is warranted; the issue stands, with a smaller and better-understood fix.
buildagent changed title from CI: neither cron has ever fired — 0 scheduled runs out of 574, so the weekly wall-clock ceilings only ever ran by hand to CI: the crons fire but github.event_name is never 'schedule', so the three weekly jobs skip on all 36 scheduled runs 2026-09-04 16:05:45 +02:00
Author
Member

Second correction: my corrected cause was ALSO wrong, in the same way. Here is the settled one, with controls.

I have now stated this cause three times. The first two were wrong, and both failed by reading the API's event column as if it were the workflow run context.

claim verdict
1st "neither cron has ever fired" (from ?event=schedule returning nothing) wrong — the filter is vacuous; the trigger is in trigger_event, and there are 36
2nd "Forgejo sets event: push, so github.event_name is never 'schedule'" wrong — same mistake, one layer up
3rd github.event_name is 'schedule'; the empty field is github.event.schedule settled by two controls

Forgejo fills the API's event column from the originating push, and the run context's event_name from trigger_event. Only the event payload stays the push's — which is exactly why github.event.schedule is the field that is empty.

The two controls, opposite signs

Negative, in this repo. corpus's old guard began with github.event_name != 'schedule'. If event_name were push, that disjunct is true and the job runs. It was skipped on all 36 scheduled runs (191, 264, 282, 386, 565…). That is impossible unless event_name == 'schedule'.

Positive, h-dv/ixt on the same instance. Two jobs in its nightly.yml are gated github.event_name == 'schedule' || …: 163 executions on scheduled runs (159 success, 4 failure), 54 skipped on pushes. The guard firing on the cadence it names and refusing the one it does not.

So github.event_name == 'schedule' is the predicate with 163 proven firings here, and every if: comparing github.event.schedule is permanently false.

And my original "the tier-1 corpus job is fine" was wrong too

Same root cause. corpus was skipped on all 36 scheduled runs, including the 32 nightlies whose entire purpose was to run it. For two months the nightly was a duplicate push build.

Census of the three heavy jobs, ever:

job non-skipped executions
corpus-scale 12 — all workflow_dispatch
grammar-rebuild 4
plugin-path-cost 0 of 17 — it had never executed at all

The fix

One cron in ci.yml; github.event_name == 'schedule' || … 'workflow_dispatch' on the three heavy jobs (renamed (weekly) → (nightly)); the tier-1 corpus job loses its if: entirely.

Separate workflow files were considered and rejected with a reason: plugin-path-cost deliberately hangs off needs: [test-daemon-leg] for the quiet slot, which a second file cannot keep without duplicating the whole chain. Separate files remain the sanctioned way to add a second cadence — ixt's weekly-scale.yml is the working precedent, and ci_cadence.rs records that. Release gating untouched.

Verified, and what is NOT verified

Run 575 — workflow_dispatch of ci.yml on master at 4555887: all 13 jobs green, including Plugin path cost + pool throughput's first-ever execution (336 s), OSS corpus tier-3 scale (807 s), Grammar rebuild (105 s).

Not verified: that the new if: fires on a real scheduled run of this file. That needs the change on master plus one 03:00 UTC tick. The two controls stand in for it, but they are not it. This issue stays open until the first nightly after the push proves it — checked with the trigger_event query, which is now written into ci.yml itself.

The probe, built as a shape rather than a check

A run-list probe cannot see a predicate — it can only see outcomes, and a skipped job looks identical whether its guard is wrong or right. So the broken shape was made unwritable instead: crates/indexer/tests/ci_cadence.rs forbids any if: comparing github.event.schedule, allows ≤1 cron per workflow, requires every schedule-gated job to accept workflow_dispatch, requires a cron and a job using it to exist together, and requires the WORKFLOWS list to equal the directory. 6 mutations run, all RED, re-run after a mid-work parser refactor.

Still open and stated in the file: nothing notices if the scheduler stops. The right home is a staleness check in the release gate, deliberately not shipped unverified.

Also fixed in passing

The seven→nine corpus drift, in ci.yml, corpus.toml, fetch.sh and corpus/mod.rs. (README:520 left alone — it is a dated v0.9.0 changelog row, true when written.) Ledger rows D33g marked REFUTED and D44g HALF REFUTED, with a dated correction section, because three source files cite them by name.

## Second correction: my corrected cause was ALSO wrong, in the same way. Here is the settled one, with controls. I have now stated this cause three times. The first two were wrong, and both failed by **reading the API's `event` column as if it were the workflow run context**. | | claim | verdict | |---|---|---| | 1st | "neither cron has ever fired" (from `?event=schedule` returning nothing) | **wrong** — the filter is vacuous; the trigger is in `trigger_event`, and there are 36 | | 2nd | "Forgejo sets `event: push`, so `github.event_name` is never `'schedule'`" | **wrong** — same mistake, one layer up | | 3rd | `github.event_name` **is** `'schedule'`; the empty field is `github.event.schedule` | **settled by two controls** | Forgejo fills the API's **`event` column** from the originating push, and the run context's **`event_name`** from `trigger_event`. Only the event **payload** stays the push's — which is exactly why `github.event.schedule` is the field that is empty. ### The two controls, opposite signs **Negative, in this repo.** `corpus`'s old guard *began* with `github.event_name != 'schedule'`. If `event_name` were `push`, that disjunct is **true** and the job runs. It was `skipped` on **all 36** scheduled runs (191, 264, 282, 386, 565…). That is impossible unless `event_name == 'schedule'`. **Positive, `h-dv/ixt` on the same instance.** Two jobs in its `nightly.yml` are gated `github.event_name == 'schedule' || …`: **163 executions on scheduled runs (159 success, 4 failure), 54 `skipped` on pushes.** The guard firing on the cadence it names and refusing the one it does not. So `github.event_name == 'schedule'` is the predicate with 163 proven firings here, and every `if:` comparing `github.event.schedule` is permanently false. ### And my original "the tier-1 corpus job is fine" was wrong too Same root cause. **`corpus` was `skipped` on all 36 scheduled runs**, including the **32 nightlies whose entire purpose was to run it**. For two months the nightly was a duplicate push build. **Census of the three heavy jobs, ever:** | job | non-skipped executions | |---|---| | `corpus-scale` | 12 — all `workflow_dispatch` | | `grammar-rebuild` | 4 | | **`plugin-path-cost`** | **0 of 17 — it had never executed at all** | ### The fix One cron in `ci.yml`; `github.event_name == 'schedule' || … 'workflow_dispatch'` on the three heavy jobs (renamed `(weekly)` → `(nightly)`); the tier-1 `corpus` job loses its `if:` entirely. **Separate workflow files were considered and rejected with a reason**: `plugin-path-cost` deliberately hangs off `needs: [test-daemon-leg]` for the quiet slot, which a second file cannot keep without duplicating the whole chain. Separate files remain the sanctioned way to add a *second* cadence — `ixt`'s `weekly-scale.yml` is the working precedent, and `ci_cadence.rs` records that. Release gating untouched. ### Verified, and what is NOT verified **Run 575** — `workflow_dispatch` of `ci.yml` on master at `4555887`: **all 13 jobs green**, including `Plugin path cost + pool throughput`'s **first-ever execution** (336 s), `OSS corpus tier-3 scale` (807 s), `Grammar rebuild` (105 s). **Not verified:** that the new `if:` fires on a real *scheduled* run of this file. That needs the change on master plus one 03:00 UTC tick. The two controls stand in for it, but they are not it. **This issue stays open until the first nightly after the push proves it** — checked with the `trigger_event` query, which is now written into `ci.yml` itself. ### The probe, built as a shape rather than a check A run-list probe cannot see a predicate — it can only see outcomes, and a skipped job looks identical whether its guard is wrong or right. So the broken shape was made **unwritable** instead: `crates/indexer/tests/ci_cadence.rs` forbids any `if:` comparing `github.event.schedule`, allows ≤1 cron per workflow, requires every schedule-gated job to accept `workflow_dispatch`, requires a cron and a job using it to exist together, and requires the `WORKFLOWS` list to equal the directory. **6 mutations run, all RED**, re-run after a mid-work parser refactor. Still open and stated in the file: **nothing notices if the scheduler stops.** The right home is a staleness check in the release gate, deliberately not shipped unverified. ### Also fixed in passing The seven→nine corpus drift, in `ci.yml`, `corpus.toml`, `fetch.sh` and `corpus/mod.rs`. (`README:520` left alone — it is a dated v0.9.0 changelog row, true when written.) Ledger rows D33g marked **REFUTED** and D44g **HALF REFUTED**, with a dated correction section, because three source files cite them by name.
buildagent changed title from CI: the crons fire but github.event_name is never 'schedule', so the three weekly jobs skip on all 36 scheduled runs to CI: github.event.schedule is empty on this Forgejo, so every cron-gated job — including tier-1 corpus — skipped on all 36 scheduled runs 2026-09-04 16:52:51 +02:00
Author
Member

Triage 2026-09-06: CLOSING. The acceptance this issue was held open for — a real nightly proving the jobs execute — is now satisfied, and I read it off the forge myself.

This is the one in the batch where source shape was never going to be enough, because this repo's own rule is that a CI job is verified by dispatching it. So here is the dispatch.

The measurement

/api/v1/repos/h-dv/code-index/actions/tasks, filtered to run 585 (2026-09-05 05:00 local = 03:00 UTC), the first nightly after 1aa6514 landed:

run 585 jobs: 13
  success | schedule | Grammar rebuild from source (nightly)
  success | schedule | OSS corpus (tier 1)
  success | schedule | OSS corpus tier-3 scale (nightly)
  success | schedule | Plugin path cost + pool throughput (nightly)
  success | schedule | cargo check (MSRV 1.98)
  success | schedule | cargo check (windows-gnu)
  success | schedule | cargo clippy
  success | schedule | cargo deny
  success | schedule | cargo doc (intra-doc links)
  success | schedule | cargo fmt
  success | schedule | cargo test
  success | schedule | cargo test (abi, 32-bit + wasm32)
  success | schedule | cargo test (daemon transport)

All 13 executed. None skipped. Every one event: schedule. Against the filing's "0 schedule out of 574 runs" and "skipped on all 36 scheduled runs", including plugin-path-cost, which had never executed at all.

Run 607 (2026-09-06 05:00) repeats it: 13 jobs, all dispatched by schedule. Three of them failed — that is separate work, and it is the right kind of problem to have, because those jobs are now capable of failing.

That matters beyond this issue: corpus-scale carries the weekly wall-clock ceiling, and this project's hardest-won finding is that correctness gates cannot see slowdowns — a 3.2× cold-index regression passed ~1950 tests and CI 10/10 three times, and only that ceiling caught it. It had never run on its own schedule until now.

The source shape, for completeness

  • One cron: .forgejo/workflows/ci.yml:287 (- cron: "0 3 * * *"), reasoning at :216-286.
  • Guards are on github.event_name, not github.event.schedule: ci.yml:1038, :1152, :1397. All nine remaining occurrences of github.event.schedule are comments.
  • Tier-1 corpus carries no if: at all — ci.yml:806.
  • The broken shape is now unwritable: crates/indexer/tests/ci_cadence.rs, whose no_job_discriminates_on_a_cron_expression is the gate that makes re-introducing it red.
$ export CARGO_INCREMENTAL=0
$ cargo test -p code-index-indexer --test ci_cadence
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
EXIT=0

#162 asks the next question — nothing notices if the scheduler stops firing again. A liveness gate exists (.forgejo/scripts/schedule_liveness.sh, release.yml:229), but it runs only at the release gate, so #162 stays open on its own terms. Closing this one does not close that one.

🤖 Triage lane, 2026-09-06, master 45cf6e4

## Triage 2026-09-06: CLOSING. The acceptance this issue was held open for — **a real nightly proving the jobs execute** — is now satisfied, and I read it off the forge myself. This is the one in the batch where source shape was never going to be enough, because this repo's own rule is that **a CI job is verified by dispatching it**. So here is the dispatch. ### The measurement `/api/v1/repos/h-dv/code-index/actions/tasks`, filtered to run **585** (2026-09-05 05:00 local = 03:00 UTC), the first nightly after `1aa6514` landed: ``` run 585 jobs: 13 success | schedule | Grammar rebuild from source (nightly) success | schedule | OSS corpus (tier 1) success | schedule | OSS corpus tier-3 scale (nightly) success | schedule | Plugin path cost + pool throughput (nightly) success | schedule | cargo check (MSRV 1.98) success | schedule | cargo check (windows-gnu) success | schedule | cargo clippy success | schedule | cargo deny success | schedule | cargo doc (intra-doc links) success | schedule | cargo fmt success | schedule | cargo test success | schedule | cargo test (abi, 32-bit + wasm32) success | schedule | cargo test (daemon transport) ``` **All 13 executed. None skipped. Every one `event: schedule`.** Against the filing's *"0 schedule out of 574 runs"* and *"skipped on all 36 scheduled runs"*, including `plugin-path-cost`, which had never executed at all. Run 607 (2026-09-06 05:00) repeats it: 13 jobs, all dispatched by `schedule`. Three of them failed — that is separate work, and it is the *right* kind of problem to have, because those jobs are now capable of failing. That matters beyond this issue: `corpus-scale` carries the weekly wall-clock ceiling, and this project's hardest-won finding is that **correctness gates cannot see slowdowns** — a 3.2× cold-index regression passed ~1950 tests and CI 10/10 three times, and only that ceiling caught it. It had never run on its own schedule until now. ### The source shape, for completeness - One cron: `.forgejo/workflows/ci.yml:287` (`- cron: "0 3 * * *"`), reasoning at `:216-286`. - Guards are on `github.event_name`, not `github.event.schedule`: `ci.yml:1038`, `:1152`, `:1397`. All nine remaining occurrences of `github.event.schedule` are comments. - Tier-1 `corpus` carries **no** `if:` at all — `ci.yml:806`. - The broken shape is now unwritable: `crates/indexer/tests/ci_cadence.rs`, whose `no_job_discriminates_on_a_cron_expression` is the gate that makes re-introducing it red. ``` $ export CARGO_INCREMENTAL=0 $ cargo test -p code-index-indexer --test ci_cadence test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out EXIT=0 ``` ### Related, and deliberately left open **#162** asks the next question — *nothing notices if the scheduler stops firing again*. A liveness gate exists (`.forgejo/scripts/schedule_liveness.sh`, `release.yml:229`), but it runs only at the release gate, so #162 stays open on its own terms. Closing this one does not close that one. 🤖 Triage lane, 2026-09-06, master `45cf6e4`
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
h-dv/code-index#109
No description provided.