Skip to content

Release ordering change opened three failure windows between local tag and published Release - #1023

Merged
xqliu merged 9 commits into
mainfrom
orbi/orbi-build-orbi-issue-1018
Sep 17, 2026
Merged

xqliu merged 9 commits into
mainfrom
orbi/orbi-build-orbi-issue-1018

Conversation

@xqliu

@xqliu xqliu commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Fixes #1018

Release ordering change opened three failure windows between local tag and published Release (run_id=de883a94)

Built by Orbi from Issue #1018 · https://github.com/orbi-build/orbi

@github-actions

Copy link
Copy Markdown
Contributor

CI failure re-occurred (job tests, same fingerprint):

Updated by the CI Failure Issue workflow (.github/workflows/ci-failure-issue.yml).

@xqliu

xqliu commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator Author

Orbi review round 1 for PR #1023: 0 blocker(s), 1 major(s).

Findings

  • Level: Major
    Location: src/orbi/release.py:2377
    Note: If publish_release fails after the tag is pushed, rollback_release_docs removes the docs commit while leaving the remote tag published. CI can then observe a released tag without its docs page, violating acceptance criteria feat: configure two-source bootstrap queue #5.
    Fix: Use a compensation strategy that preserves docs for every published tag; do not revert the pushed docs commit unless the unpublished tag is safely removed, or redesign publication ordering transactionally.

@github-actions

Copy link
Copy Markdown
Contributor

CI failure re-occurred (job tests, same fingerprint):

Updated by the CI Failure Issue workflow (.github/workflows/ci-failure-issue.yml).

@xqliu

xqliu commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator Author

Maintainer: the round-1 finding is correct — confirmed by reading the call site

The rollback fires on docs_commit is not None alone:

except Exception:
    if docs_commit is not None:
        rollback_release_docs(...)
    raise

It never checks whether the tag has already been pushed. And in this very flow ensure_release_tag_pushed runs before publish_release — that ordering is the #998 fix. So whenever publish_release fails:

The compensation closes window 2 (a (latest) page linking to a Release that 404s) by reopening the window #998 closed. Acceptance criterion 5 (CI never observes a released tag without its docs page) is violated, as the reviewer says.

Direction

The two windows cannot both be closed by compensating after the fact — they are on opposite sides of the same ordering. Whatever shape the fix takes, it has to make the failure state unambiguous:

  • Roll back the docs commit only when the tag was not pushed (that state is knowable: ensure_release_tag_pushed either ran or did not), and leave the docs in place once a tag exists — a page whose link 404s for a few minutes is strictly less harmful than a released tag with no docs, and the next attempt will publish the Release for that same tag.
  • Or make the (latest) marker move only after publication, so a failed publish leaves the previous release as (latest) and the new page merely unreferenced.

Either way criterion 5 stays the hard one: it is the invariant an automated CI check keys on, whereas the 404 link is a transient a human sees.

On the ticket itself

Ticket #1018 listed three windows plus the counter issue. If closing window 2 properly requires a different publication design than window 1 and 3, splitting is acceptable — say so on the Issue and deliver the ones that are independently fixable, rather than forcing a compensation that trades one invariant for another.

@github-actions

Copy link
Copy Markdown
Contributor

CI failure re-occurred (job tests, same fingerprint):

Updated by the CI Failure Issue workflow (.github/workflows/ci-failure-issue.yml).

@github-actions

Copy link
Copy Markdown
Contributor

CI failure re-occurred (job tests, same fingerprint):

Updated by the CI Failure Issue workflow (.github/workflows/ci-failure-issue.yml).

@xqliu

xqliu commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator Author

CI failure is the patch ratchet, not a logic error — and --update is not the way out

patch ratchet FAILED: new test patches are ratcheted shut (Issue #789).
command_shape_asserts 519 > 517

The new tests assert on the shape of command arrays (command[:N] == [...]), which tools/patch_ratchet.py counts and refuses to let grow. Its own message states the rule:

Migrate to tests/fakes/ (state + public entry + public surface, zero monkeypatch.setattr(runner, ...)) or remove the pattern; --update is only for a PR that LOWERS the counts

tests/fakes/ already provides github.py, gitops.py and launchd.py. Tests for this ticket should drive the release path through those fakes and assert on observable outcomes — which refs exist, what the docs page contains, whether the Issue was commented — rather than on the exact argv passed to git.

That is also a better fit for what this ticket is about: the acceptance criteria are all about state after a failure (is there a tag residue, does the docs page exist, does the marker point at the right release), none of which need command-shape assertions.

Running --update to raise the counter would pass CI while doing the opposite of what Issue #789 established. Please don't.

Note on scope

Acceptance item 2 was rewritten on the Issue after round 1: reverting the docs commit is explicitly ruled out as a compensation, because ensure_release_tag_pushed runs before publish_release and the revert would leave a released tag without docs — the exact bug #998 removed. Two workable directions are listed there, and splitting the ticket is acceptable if item 2 needs a different publication design than items 1 and 3.

@github-actions

Copy link
Copy Markdown
Contributor

CI failure re-occurred (job tests, same fingerprint):

Updated by the CI Failure Issue workflow (.github/workflows/ci-failure-issue.yml).

@github-actions

Copy link
Copy Markdown
Contributor

CI failure re-occurred (job tests, same fingerprint):

Updated by the CI Failure Issue workflow (.github/workflows/ci-failure-issue.yml).

@xqliu

xqliu commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator Author

Orbi review round 2 for PR #1023: 0 blocker(s), 1 major(s).

Findings

  • Level: Major
    Location: src/orbi/release.py:1752
    Note: Current-head CI fails the required diff coverage gate; new release-doc promotion branches remain uncovered.
    Fix: Add tests covering all newly introduced promotion, resume, deduplication, and tag-push compensation branches, then rerun CI until the tiered coverage gate passes.

@xqliu

xqliu commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator Author

Maintainer: this is the right design — it closes both windows instead of trading them

The new shape (promote release docs after publication + keep docs latest promotion idempotent) takes the second direction listed on the Issue, and it works where the round-1 compensation could not:

def release_docs_page(..., latest: bool = True):
    title = f"# {version} release" + (" (latest)" if latest else "")

def promote_release_docs_latest(*, worktree, base_branch, ...):
    """Promote a successfully published release to the docs latest slot."""

The docs page now lands before the tag as a non-latest page, and the (latest) marker moves only after publish_release succeeds. That resolves both windows at once rather than trading one for the other:

  • publish_release fails → the new page exists but is not (latest); the previous release keeps the marker. No (latest) page linking to a Release that 404s.
  • The tag is already pushed at that point → the docs page stays where it is, nothing is reverted. Criterion 5 holds: CI never sees a released tag without its docs page.

This is strictly better than round 1's rollback_release_docs, which closed window 2 by reopening the bug #998 removed.

Remaining CI failure is coverage, not logic

The patch ratchet now passes (command_shape_asserts is no longer growing — thank you for migrating rather than running --update). What's left:

diff gate FAILED: changed Python code is not 100% covered
  src/orbi/release.py:1763, 1772, 1779, 1903
  src/orbi/release.py:1752: changed branch to line 1749 not covered

Those are the new latest parameter branches and the promotion helper. Both are reachable through the fakes in tests/fakes/ without command-shape assertions — the same route that got the ratchet green.

Acceptance status

@xqliu

xqliu commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator Author

Orbi needs a fix: the independent review of PR #1023 failed: PR #1023 head moved after base absorb (absorbed=a5538d15d9f46333099d0c075fa58a718c54949d remote=701d296bba01e920805741dc05cadb0e865849a7); the Issue stays ai-fix-needed and the next tick resumes the same run, branch, worktree and PR
run=de883a94 issue=#1018 role=review branch=orbi/orbi-build-orbi-issue-1018 worktree=/home/xqianliu/Projects/orbi/orbi/.worktrees/orbi-orbi-build-orbi-issue-1018-de883a94 session=01a0ae63-7f26-72e1-85e4-f525f38735ad session_file=/home/xqianliu/Projects/orbi/orbi/.worktrees/orbi-orbi-build-orbi-issue-1018-de883a94/.pi-session/2026-09-17T08-02-31-335Z_01a0ae63-7f26-72e1-85e4-f525f38735ad.jsonl phase=bash last_activity=2026-09-17T08:34:46.317Z action="assistant text" result=-

Failure evidence (captured before cleanup):
exit_code=

stderr_tail:

<empty>

stdout_tail:

<empty>

session_last_events (last 20 records; full log: /home/xqianliu/Projects/orbi/orbi/.worktrees/orbi-orbi-build-orbi-issue-1018-de883a94/.pi-session/2026-09-17T08-02-31-335Z_01a0ae63-7f26-72e1-85e4-f525f38735ad.jsonl):

2026-09-17T08:20:24.865Z message role=toolResult tool=edit content=text
2026-09-17T08:20:38.163Z message role=assistant content=thinking,toolCall:bash
2026-09-17T08:20:40.215Z message role=toolResult tool=bash content=text
2026-09-17T08:20:53.330Z message role=assistant content=thinking,toolCall:bash
2026-09-17T08:24:57.417Z message role=toolResult tool=bash content=text
2026-09-17T08:25:08.197Z message role=assistant content=thinking,toolCall:edit
2026-09-17T08:25:08.255Z message role=toolResult tool=edit content=text
2026-09-17T08:25:13.016Z message role=assistant content=thinking,toolCall:bash
2026-09-17T08:25:15.470Z message role=toolResult tool=bash content=text
2026-09-17T08:25:24.216Z message role=assistant content=thinking,toolCall:bash
2026-09-17T08:29:23.458Z message role=toolResult tool=bash content=text
2026-09-17T08:29:27.430Z message role=assistant content=thinking,toolCall:bash
2026-09-17T08:29:31.010Z message role=toolResult tool=bash content=text
2026-09-17T08:29:35.845Z message role=assistant content=thinking,toolCall:bash
2026-09-17T08:29:37.348Z message role=toolResult tool=bash content=text
2026-09-17T08:29:40.905Z message role=assistant content=thinking,toolCall:bash
2026-09-17T08:34:39.313Z message role=toolResult tool=bash content=text
2026-09-17T08:34:42.910Z message role=assistant content=thinking,toolCall:bash
2026-09-17T08:34:42.919Z message role=toolResult tool=bash content=text
2026-09-17T08:34:46.317Z message role=assistant content=thinking,text

test_log_tail:

            installed_unit_dir=lambda: installed,
            unit_config=lambda path: config if path == unit else None,
        )
        monkeypatch.setattr(orbi.scheduler, "detect", lambda: fake)
        with caplog.at_level(logging.ERROR, logger="orbi.cli"):
            assert orbi.main(["milestone", "set", "v1"]) == 1
>       assert "config_not_found" in caplog.text
E       AssertionError: assert 'config_not_found' in ''
E        +  where '' = <_pytest.logging.LogCaptureFixture object at 0x7f71dea7d390>.text

tests/test_orbi.py:1079: AssertionError
----------------------------- Captured stderr call -----------------------------
milestone_set_failed reason=milestone_not_found title='v1' repo=orbi-build/orbi open milestones: v0.6.0(10), v0.5.17(4); fix=use one exact title from `gh api repos/orbi-build/orbi/milestones?state=open --jq '.[].title'`
=========================== short test summary info ============================
FAILED tests/test_orbi.py::test_check_reports_missing_config_when_no_unit_is_available
FAILED tests/test_orbi.py::test_status_resolves_the_single_existing_installed_unit_config
FAILED tests/test_orbi.py::test_status_does_not_guess_between_installed_unit_configs
FAILED tests/test_orbi.py::test_mutating_command_lists_a_unit_config_without_using_it
4 failed, 3237 passed in 226.43s (0:03:46)
pytest_exit=1

zzuu080603 pushed a commit to zzuu080603/orbi that referenced this pull request Sep 25, 2026
The README pointed at Issue orbi-build#835 → PR orbi-build#843 → v0.5.4, the same stale loop
the old demo video showed. Retarget both READMEs to orbi-build#1018 → orbi-build#1023 → v0.5.17
and embed the current 35s cut inline.

GitHub renders <video> natively in README (verified against a live repo),
so no GIF conversion is needed. The mp4 is 0.77MB, well under the 10MB limit,
H.264/AAC as recommended.

The video's numbers were checked against the live record: Issue orbi-build#1018 closed
ai-merged, PR orbi-build#1023 merged with 9 commits / +427 / -43, v0.5.17 published.

Claude-Session: https://claude.ai/code/session_0196a575kBse7AK3CBXs8g5J
@orbi-build
orbi-build Bot deleted the orbi/orbi-build-orbi-issue-1018 branch September 28, 2026 18:42
zzuu080603 pushed a commit to zzuu080603/orbi that referenced this pull request Sep 30, 2026
…rbi-build#1424)

Replace the superseded orbi-build#1018 -> orbi-build#1023 -> v0.5.17 inspect line with the film's
poster and the run it follows (orbi-build#1367 -> orbi-build#1370 -> v0.5.47) in both READMEs,
and tighten Quick start / development wording so README.md stays inside the
8 KiB homepage budget with MAX_BYTES/MAX_LINES unchanged.

Fixes orbi-build#1424
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.

Release ordering change opened three failure windows between local tag and published Release

1 participant