Skip to content

xtask: add topological-order guard to publish-check (post-#565 hardening)#572

Merged
EffortlessSteven merged 1 commit into
mainfrom
xtask/publish-check-topo-guard
May 11, 2026
Merged

xtask: add topological-order guard to publish-check (post-#565 hardening)#572
EffortlessSteven merged 1 commit into
mainfrom
xtask/publish-check-topo-guard

Conversation

@EffortlessSteven

Copy link
Copy Markdown
Member

Why

The v0.7.0 release lane hit a publish failure because PUBLISH_CRATES in xtask/src/main.rs had compatibility shims listed before their owner crates. Specifically uselesskey-core-seed (a shim that depends on uselesskey-core) was at index 0 while uselesskey-core was at index 21. cargo xtask publish walks the list in order, so it tried to publish uselesskey-core-seed v0.7.0 first and cargo publish failed because uselesskey-core ^0.7.0 was not on crates.io yet.

PR #565 reordered PUBLISH_CRATES to put owners before shims. However, the existing cargo xtask publish-check did not catch the bug locally because its dry-run mode (cargo package --no-verify) resolves workspace deps against local paths, not against crates.io. The misorder was only visible against the live registry.

This PR closes that local gap so a future reorder fails the developer's pre-push gate instead of the live publish workflow.

What

  • New verify_publish_order_is_topological() in xtask/src/main.rs:
    • Runs cargo metadata --format-version 1 --no-deps.
    • For every crate in PUBLISH_CRATES, collects its workspace dependencies (normal, dev, and build kinds, via the dependencies array cargo metadata exposes).
    • For each (crate, dep) pair where both are in PUBLISH_CRATES, asserts the position of dep is less than the position of crate.
    • On any violation, returns Err listing each inverted pair in the form uselesskey-foo (#N) depends on uselesskey-bar (#M) but uselesskey-bar is listed later.
  • publish_check() now calls this function before any cargo publish --dry-run work, so the topological invariant is enforced in the same command the release lane already runs.
  • New unit test publish_order_is_topological() calls the verifier and asserts Ok as a sanity guard against accidental reorders.

Inversions today

Zero. Against main HEAD the new guard is a no-op; PR #565 already left PUBLISH_CRATES in a valid topological order. This PR is purely future-proofing.

Test plan

  • cargo build -p xtask (clean)
  • cargo test -p xtask publish_order_is_topological (1 passed)
  • cargo xtask publish-check (clean; new guard runs first, no order violations)
  • cargo fmt --check -p xtask (clean)
  • cargo clippy -p xtask --all-targets -- -D warnings (clean)
  • CI green is the merge gate

…ing)

The v0.7.0 release lane hit a publish failure because PUBLISH_CRATES had
compatibility shims listed before their owners: uselesskey-core-seed (a
shim that depends on uselesskey-core) was at index 0 while
uselesskey-core was at index 21. cargo xtask publish walks the list in
order, so it tried to publish uselesskey-core-seed v0.7.0 first and
cargo publish failed because uselesskey-core ^0.7.0 was not on
crates.io yet.

PR #565 reordered PUBLISH_CRATES to put owners before shims, but the
existing cargo xtask publish-check did not catch the bug locally because
its dry-run mode (cargo package --no-verify) resolves workspace deps
against local paths, not crates.io. The bug was only visible against the
live registry.

This adds a verify_publish_order_is_topological() function that uses
cargo metadata to walk every (crate, workspace-dep) pair in
PUBLISH_CRATES and asserts the dep is listed earlier. publish_check now
calls it before any dry-runs so a future reorder fails the local gate
before it can break the live publish. A matching unit test
(publish_order_is_topological) keeps the current ordering honest.

0 inversions exist today; the guard is a no-op against main HEAD.
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@EffortlessSteven has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 45 minutes and 20 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5cbbd21d-d2dd-45d6-8b2b-eb18ed6594c8

📥 Commits

Reviewing files that changed from the base of the PR and between 1a5b944 and 9e56fe9.

📒 Files selected for processing (1)
  • xtask/src/main.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch xtask/publish-check-topo-guard

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@EffortlessSteven EffortlessSteven merged commit 580ac05 into main May 11, 2026
6 checks passed
EffortlessSteven added a commit that referenced this pull request May 11, 2026
Why patch mode
==============

v0.7.0 ran the full minor-release evidence lane, including expensive
gates like `cargo xtask mutants-nightly --scope public`, the broad
perf suite, and new product profile proofs. That investment is right
for a minor release that changes the user-facing platform.

v0.7.1 is different: it hardens release tooling and the user install
path without changing public behavior. It only needs confidence that
release-system gates and the user path still work. Running the full
minor lane on every patch wastes CI time and dulls the signal of the
minor lane itself.

What the patch lane runs
========================

`cargo xtask release-evidence --version <V> --patch [--summary]`
selects `release_evidence_steps_patch()` which runs 10 focused steps:

1.  `public-surface`            — re-confirm exported API
2.  `check-file-policy`         — non-Rust file allowlist
3.  `publish-preflight`         — metadata + cargo package --no-verify
4.  `publish-check`             — ordered publish dry-runs (includes
                                  topology guard from #572 and
                                  publish=false dep guard from #578)
5.  `scanner-safe-reference --check` (#577) — scanner reference paths
6.  `cratesio-smoke --path . --skip-install-cli` (#580) — user path
7.  `docs-sync --check`         — docs are in sync with code
8.  `no-blob`                   — no secret-shaped blobs in test paths
9.  `examples-smoke`            — examples still compile / run
10. `impacted-evidence --base origin/main` — change-impact routing

What it deliberately omits
==========================

- `mutants-nightly --scope public` — full nightly mutation runs
  against `main` on schedule; targeted mutation already runs through
  `cargo xtask pr` when `impacted-evidence` flags the change.
- broad perf suite (`perf --compare`) — patch releases should not
  shift baselines; if they do, escalate to the minor lane.
- new product profile proofs (scanner-safe bundle, OIDC contract
  pack) — patch releases are not the venue to re-prove new profiles.

Receipt shape
=============

`ReleaseEvidenceReceipt` gains a `lane_mode` field (`"minor"` or
`"patch"`). The existing `lane: "release-evidence"` string is
preserved for backward compatibility with anything consuming the
shape; only the new field distinguishes the two lanes. The
release-evidence markdown gains a `Mode:` line; the summary opens
with a "Patch-mode evidence lane" callout when patch is set and
swaps the v0.7.0-specific gate table for the patch step list.

Tests
=====

- `release_evidence_patch_step_list_excludes_mutants_nightly`
- `release_evidence_minor_step_list_includes_mutants_nightly`
- `release_evidence_patch_step_list_includes_scanner_safe_reference`
- `release_evidence_patch_step_list_includes_cratesio_smoke`
- `release_evidence_patch_receipt_records_patch_mode`
- `release_evidence_patch_summary_announces_patch_lane`

Minor-lane callers (`release-evidence --version X [--summary]` with
no `--patch`) are unchanged in behavior and continue to run the
full 15-step lane.
@EffortlessSteven EffortlessSteven mentioned this pull request May 11, 2026
4 tasks
EffortlessSteven added a commit that referenced this pull request May 11, 2026
Bump workspace version 0.7.0 -> 0.7.1 and seed the CHANGELOG entry
describing the release-hardening additions (#572, #577, #578, #580,
#581) and docs (#571, #579). No new product surface; no shim removal;
no profile work. Patch evidence lane passes.
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.

1 participant