Skip to content

shipper publish: plan order appears alphabetical rather than topological; first-listed crate has unmet workspace deps #173

Description

@EffortlessSteven

Summary

`shipper publish` (and `shipper plan`) appear to emit packages in alphabetical order rather than topological order over the workspace dependency DAG. The first crate in the plan has workspace deps that are not yet on crates.io, so `cargo publish` fails on the first attempt and the run halts.

Version

`shipper 0.3.0-rc.2` (installed via `cargo install shipper --locked --version 0.3.0-rc.2` in GitHub Actions).

Workspace

`EffortlessMetrics/uselesskey` at tag `v0.7.0` (commit `69ab4b4`). 53 publishable crates, 11 `publish = false` workspace-only crates.

Plan output (workflow log)

```
plan_id: e758bf7167af19ee8ca3028c322bd020d0c3ef872b340d5ee2717f0c5d701c1d
registry: crates-io (https://crates.io)
Total packages to publish: 53

  1. uselesskey-aws-lc-rs@0.7.0
  2. uselesskey-core@0.7.0
  3. uselesskey-core-cache@0.7.0
    ...
  4. uselesskey-entropy@0.7.0
  5. uselesskey-jwk@0.7.0
  6. uselesskey-core-jwk@0.7.0
    ...
  7. uselesskey-ecdsa@0.7.0
  8. uselesskey-rsa@0.7.0
    ```

Note position 1: `uselesskey-aws-lc-rs` lists `uselesskey-core` (#2), `uselesskey-rsa` (#29), `uselesskey-ecdsa` (#22), `uselesskey-ed25519` as direct dependencies in `[dependencies]` — all required to be on crates.io at `^0.7.0` for cargo publish to succeed.

Symptom (failing publish run)

When publish runs against this plan:

```
[1/53] Publishing uselesskey-aws-lc-rs@0.7.0... (1.533µs)
[warn] uselesskey-aws-lc-rs@0.7.0: cargo publish failed (exit=101); checking registry...
[warn] uselesskey-aws-lc-rs@0.7.0: publish outcome ambiguous; registry did not show version (Ambiguous); next attempt in 7s 373ms (attempt 2/12)
... (12 retries with exponential backoff, all failing identically) ...
Error: uselesskey-aws-lc-rs@0.7.0: failed: publish outcome ambiguous; registry did not show version
```

The underlying `cargo publish` error (suppressed in the retry summary) is the expected "required dep not yet on crates.io":

```
error: failed to prepare local package for uploading
Caused by: failed to select a version for the requirement `uselesskey-ecdsa = "^0.7.0"`
```

Reproduces locally with the same workspace state:

```
$ cargo publish --dry-run -p uselesskey-aws-lc-rs --allow-dirty
```

The expected resolution would be to publish `uselesskey-ecdsa` (and the other true leaves) first, then iterate up the DAG until `uselesskey-aws-lc-rs` is reachable.

Expected behavior

`shipper plan` should emit crates in topological order over the workspace dependency DAG (parents before children), so that `shipper publish` walking the plan linearly always finds the current crate's deps already on crates.io.

A leaf-first ordering would put `uselesskey-core-hmac-spec` (no workspace deps) at #1, then crates whose only workspace dep is core-hmac-spec, etc., ending with the facade `uselesskey@0.7.0` and the adapters that depend on it.

What we tried

  • `shipper preflight --policy safe --allow-dirty` ran clean.
  • `shipper publish --policy safe --readiness-method both --max-attempts 12 --max-delay 15m --allow-dirty` failed with the above 12-retry loop.
  • Tag was retagged at a commit with all dev-dep / workspace fixes applied; plan_id was identical to a prior run, suggesting the ordering is deterministic over workspace structure and not influenced by upstream commits.

Possible diagnosis

The plan output's order from #1..#53 reads as a sort by crate name (with hyphen ordering quirks). For example `uselesskey-jwk` is at #16, then `uselesskey-core-jwk` at #17, which is consistent with alphabetical ordering of the part after the last hyphen, or with depth-first traversal that happens to align with alphabetical-by-package-name within sibling sets, rather than strict topo sort over the workspace DAG.

Workspace details (in case relevant)

  • Edition 2024, MSRV `1.95`.
  • Workspace internal dev-helper crates (`uselesskey-test-support`, `uselesskey-test-grid`, `uselesskey-feature-grid`) are now path-only in `workspace.dependencies` (no `version` field), explicitly `publish = false`.
  • All published crates carry workspace deps using `{ workspace = true }`.
  • The plan correctly identifies the 11 `publish = false` crates and excludes them.

Impact

We can't complete a v0.7.0 publish via shipper. Three crates (`uselesskey-core-hmac-spec`, `uselesskey-jwk`, `uselesskey-core-jwk`) landed at 0.7.0 via an earlier `cargo xtask publish` attempt with a hand-maintained order; the remaining 50 are blocked behind the publish-order issue. We've paused the release until we can confirm shipper's expected behavior here.

Happy to share the full workflow logs, plan artifacts, or a minimal repro workspace if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions