Skip to content

Redeploy main after a merge when prod has not converged on it #3848

Open

Description

@devantler

🤖 Generated by the Agentic Engineer

Part of #2838. It follows #3846, whose resolver merged in #3847.

Evidence

Audience and impact

This serves the platform operator. It closes the last path by which prod can silently disagree with main after a merge.

Smallest useful change

After a merge lands on main, run the resolver against the digest :latest names:

  • CONVERGED: do nothing.
  • BEHIND or DIVERGED: run the normal production deploy of main, through the same composite and the shared prod-deploy lock.
  • UNKNOWN: do not deploy; fail visibly, so a broken check is never mistaken for a converged prod.

Because this job reaches production, it inherits every gate the existing deploy paths carry: the publication gate, the authorization and signing contracts, and the per-workflow coverage guards. It lands behind an opt-in switch, defaulting off, and is activated separately.

Acceptance criteria

  • On a merge where prod already matches main, the job reads CONVERGED and does not deploy (proven on a real merge).
  • A BEHIND or DIVERGED verdict triggers exactly one deploy of main, and a second evaluation afterwards reads CONVERGED.
  • UNKNOWN never deploys and fails the job with the resolver's reason.
  • The job holds the shared prod-deploy lock and cannot run concurrently with a merge-group deploy or heal.
  • Tell whether prod has converged on main from the published artifact's signed provenance #3846's live CONVERGED acceptance point is recorded from this job's first real run.

Verification — 2026-11-03

The real merge Validate Main run 41663342775, at b76dd8340c2d51922e8beb65d7612c039af80c09, completed successfully. Its production-convergence job emitted CONVERGED and skipped the redeploy step. This confirms the no-deploy path and the live resolver acceptance point; it does not prove automatic recovery.

The complete seven-run CD history on main since 2026-10-26 contains no successful github-actions[bot] dispatch. The remaining acceptance is a real BEHIND observation, exactly one successful automatic deploy, then a CONVERGED recheck. As recorded in #3869 and the earlier acceptance table, DIVERGED remains a warning while a queued group may be deploying; this check does not authorize a rollback or a production trial.

Size

M: one workflow job plus contract-test updates, behind an opt-in switch.

Blocker: the next real BEHIND observation followed by one successful automatic main deployment and a CONVERGED recheck | outcome | last-verified 2026-11-03: the latest real merge observer returned CONVERGED and skipped redeployment; the complete seven-run main CD history since 2026-10-26 contains no successful automated dispatch, so the remaining recovery sequence is unverified. Collect that sequence when it occurs; no production mutation is needed for this verification

Activity

  1. added theissue type on Sep 15, 2026
  2. moved this to 📥 Backlog in 🌊 Project Boardon Sep 15, 2026
  3. devantler commented on Sep 16, 2026

    @devantler
    ContributorAuthor

    🤖 Generated by the Agentic Engineer

    First slice merged: #3864 (5e3049c9). After every push to main, a read-only job reports the resolver's verdict. CONVERGED becomes a notice. BEHIND and DIVERGED become warnings, because a queued merge group can briefly show DIVERGED. UNKNOWN fails the job. The job never deploys. Before resolving, it fetches every commit the provenance names, so an artifact left by a merge-group heal does not read as UNKNOWN. Its first live run read CONVERGED (run 35150608562).

    Acceptance criterion State
    Prod already matches main → reads CONVERGED, no deploy (real merge) Met on the #3864 merge; this slice never deploys
    BEHIND/DIVERGED triggers exactly one deploy of main, then CONVERGED Open: the deploy slice
    UNKNOWN never deploys and fails with the resolver's reason Met for the report; still to keep in the deploy slice
    Holds the shared prod-deploy lock Open: the deploy slice
    #3846's live CONVERGED point recorded Met

    Next slice: a deploy of main on BEHIND/DIVERGED under prod-deploy, behind a switch that defaults to off. It reaches production, so it carries the deploy lane's usual gates.

  4. devantler commented on Sep 17, 2026

    @devantler
    ContributorAuthor

    🤖 Generated by the Agentic Engineer

    Status 2026-09-17: the deploy slice merged as #3870 (for #3869)

    Acceptance criterion State
    Prod already matches main → reads CONVERGED, no deploy (real merge) Met. On the #3870 merge itself, run 35212406549 read CONVERGED for 1dff6239, skipped the redeploy step, and dispatched no CD run.
    BEHIND triggers exactly one deploy of main, then CONVERGED Built, not yet observed live. The observer dispatches CD on main only on BEHIND, skips when an unfinished CD run already targets main's tip, and waits for its dispatched run to be listed before releasing the lock. Proven by the script's tests. A real BEHIND needs the #2838 interleaving, so this stays open until one happens.
    DIVERGED Deliberately not redeployed. A queued merge group that deployed before merging also reads DIVERGED, so redeploying on it would undo a deploy that is about to land (decision recorded on #3869). It stays a warning.
    UNKNOWN never deploys and fails with the resolver's reason Met (unchanged from #3864).
    Holds the shared prod-deploy lock Met: the observer job takes prod-deploy with queue: max.
    #3846's live CONVERGED point recorded Met.

    Remaining: record the first live BEHIND → one CD run → CONVERGED sequence. Nothing else is left to build here.

  5. devantler commented on Sep 19, 2026

    @devantler
    ContributorAuthor

    🤖 Generated by the Agentic Engineer

    Status 2026-09-19: still waiting on a live BEHIND. Nothing is left to build.

    Across the last 100 validate-main.yaml runs, 32 reached the 🧭 Observe Production Convergence job, and every one of them recorded CONVERGED in its annotations. None recorded BEHIND, DIVERGED or UNKNOWN. The only failed run in that window (35100863274, 2026-09-16) predates the observer.

    So the one open criterion (a real BEHIND, then one CD run, then CONVERGED) is waiting for the #2838 interleaving to actually happen. There is no code change to make until it does. Any later run can re-check with the check-run annotations on that job.

  6. added 2 commits that reference this issue on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Fields

    Priority

    None yet

    Effort

    None yet

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions