Skip to content

The maps freshness gate never runs on main, so main can go stale silently #1274

Description

@sfmskywalker

The Generated maps fresh check in .github/workflows/ci.yml runs only on pull_request. Nothing runs it on push to main.

Consequence, observed rather than hypothesised

On 2026-08-10, PR #1202 added specs/149-canonical-dependency-map/ without regenerating the maps. Main then carried a stale docs/reports/maps-v1-findings.md with no failing run anywhere to report it, because no workflow ever evaluated main.

The cost transferred to the next PRs opened: three unrelated PRs (#1243, #1247, #1248) went red on a check none of them had broken. CI evaluates the PR merged into main, so a branch whose own tree is fine still fails, and -- check passes locally on the exact commit CI fails on. That discrepancy is the only available clue, and it points away from the real cause.

Why this is worth fixing rather than absorbing

It is structurally the same finding as R0 (#1246): a correct mechanism wired to one path and not the one that needed it. The freshness gate exists precisely because "the committed maps went three projects stale and carried 25 corrupted rows with nothing objecting" (its own XML doc). Running it only on pull_request recreates a narrower version of that gap: main can be stale and silent, and the check reports it to the wrong person.

Do

Add the freshness check to a push trigger on main, or a scheduled run, so main going stale is reported against main rather than against whoever opens the next PR.

Consider whether it should block or merely notify. Blocking on push is not possible after the fact, so the useful outcomes are a notification and a fast follow-up, or an auto-regenerating job that opens a PR.

Related trap worth documenting alongside

docs/maps/manifest.json is regenerated by -- all but deliberately excluded from the comparison by MapFreshness (it carries input_fingerprint and git_head, which move with every commit; its own comment calls it "bookkeeping, not a description of the tree").

Committing a regenerated manifest therefore achieves nothing the gate reads, and actively manufactures conflicts: two concurrent PRs that both regenerate maps will conflict on it, because each carries a different git_head. That is exactly what made #1247 go CONFLICTING the moment #1248 squash-merged, while #1243, where the manifest was left untouched, stayed mergeable through both merges.

Worth a line in the contribution guidance: regenerate with -- all, then stage only the changed real map files.

Start at

  • .github/workflows/ci.yml (the Generated maps fresh job)
  • tools/maps/Elsa.Maps.Generator/MapFreshness.cs (the exclusion and its rationale)

Done when

Main going stale is reported against main, and the manifest guidance is written down where a contributor will see it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions