Skip to content

ci(release): refuse a stable tag unless dig-constants is single and current - #178

Open
MichaelTaylor3d wants to merge 1 commit into
mainfrom
ci/dig-constants-release-gate
Open

ci(release): refuse a stable tag unless dig-constants is single and current#178
MichaelTaylor3d wants to merge 1 commit into
mainfrom
ci/dig-constants-release-gate

Conversation

@MichaelTaylor3d

Copy link
Copy Markdown
Contributor

Adds a release gate that refuses to cut a stable tag while dig-constants is stale or duplicated.

Why

dig-constants is the ecosystem's one source for ports, paths and shared values. Both ways that guarantee fails are silent — neither is a build error:

  • Stale — a changed (not renamed) value means this node disagrees with every component that is current, and nothing reports it. A rename fails loudly; a changed value does not.
  • Duplicated — cargo cannot unify semver-incompatible 0.x minors, so several copies link into one binary, each serving a different subsystem.

The second is the one no review catches, because every individual manifest looks reasonable.

This repo is shipping it right now

published tip : 0.9.0
in this lock  : 0.1.0  0.4.0  0.5.1  0.8.0

0.1.0  <- dig-clvm
0.4.0  <- dig-gossip, dig-node-core, dig-node-service
0.5.1  <- dig-nat, digstore-chain
0.8.0  <- dig-download

Four copies of the canonical-constants crate in one process, none of them current. If a port or protocol value moved between 0.4 and 0.8, the node's own RPC layer and its download layer disagree about it inside the same binary.

Design decisions worth reviewing

  • Reads the LOCK, not the manifest range. dig-constants = "0.4" stays "satisfied" by a 0.4.0 lock forever; only the lock says what actually compiles in.
  • Fails closed when crates.io cannot be read. A gate that passes on a network error is bypassable by causing one. The sparse index also needs a descriptive User-Agent — a bare curl 403s.
  • Placed before version resolution in the stable job, so a failure means no tag exists to deploy rather than a bad build caught later. Releasing is the moment drift escapes the repo.
  • Yanked versions are skipped when picking the published tip.

Verified, not assumed

Run against this tree it reports all four versions plus the staleness and exits 1. I checked the exit code separately from the output, because piping through head masks it — which is exactly how a gate silently passes.

Deliberately NOT a PR check yet

dig-constants is stale today, so making this a required status check would immediately block every open PR and the release it exists to protect. It gates the release only. Promote it to a PR check once #2072 brings the versions current — that is the right end state, just not the right first step.

Refs #2072

MichaelTaylor3d added a commit that referenced this pull request Aug 3, 2026
Review of the envelope fix caught that `inclusion_proof` was gated on `start == 0`,
which is the same defect this change exists to remove, relocated to large resources.

`inclusion_proof` is in `ChunkObject.required` in docs.dig.net's openrpc.json and is
documented there as "Sent on every window for getContent/getManifest"; the retired
dighub-retrieval Lambda emitted it unconditionally, gating only `chunk_lens` on the
first window. Gating the proof meant windows 1..N of any resource over 3 MiB carried
no way to verify, and a client that begins mid-resource — a resumed or ranged read —
never received one at all. A well-formed response the client cannot verify, with no
error raised anywhere, is exactly the failure mode of #2071. chia-offer.on.dig.net is
15962 bytes and fits in a single window, which is why testing against it could not
have surfaced this.

`chunk_lens` keeps its first-window-only rule, which both normative sources agree on:
it describes how to split the reassembled resource, which a client cannot act on
until it holds every window.

SPEC.md §5.5.0 is corrected and completed:

  * the field table now matches ChunkObject field-for-field, and says so, so the two
    normative sources cannot drift again without one of them contradicting the other
    in writing
  * states the 3 MiB window, and that this node IGNORES the `length` request
    parameter while openrpc documents it as honoured-then-clamped, so a client sizes
    its stride from the length it is GIVEN
  * names all three independent definitions of the window size (WINDOW here,
    RPC_MAX_CHUNK in hub's retrieval Lambda, RPC_CHUNK in on.dig.net's service
    worker) and references DIG-Network/dig_ecosystem#2076 to consolidate them into
    dig-constants
  * drops the inaccurate "every path, one shared builder" claim: the response-window
    cache replays a proxied upstream result verbatim rather than rebuilding it, which
    is deliberate (it preserves provenance) and is now stated as the exception

The window-size consolidation is deliberately NOT done here. dig-node carries four
versions of dig-constants (#2072) and PR #178 adds a release gate requiring it to be
single and current, so adding a constant means a version reconciliation this outage
fix should not be coupled to.

Tests: a new test asserts the proof on both the first and last window of a
multi-window resource, and that only the first carries chunk_lens. Falsified by
re-gating the proof on `start == 0` — the last-window assertion fails. 670/670
dig-node-core lib tests pass.

Refs DIG-Network/dig_ecosystem#2071

Co-Authored-By: Claude <noreply@anthropic.com>
…urrent

dig-constants is the ecosystem's one source for ports, paths and shared
values, and both ways that guarantee fails are SILENT — neither is a build
error:

  stale       a CHANGED (not renamed) value means this node disagrees with
              every component that is current, and nothing reports it.
  duplicated  cargo cannot unify semver-incompatible 0.x minors, so several
              copies link into ONE binary, each serving a different
              subsystem.

The second is the one no review catches, because every individual manifest
looks reasonable. This repo is shipping it right now — the lock carries FOUR
dig-constants against a published 0.9.0:

  0.1.0  <- dig-clvm
  0.4.0  <- dig-gossip, dig-node-core, dig-node-service
  0.5.1  <- dig-nat, digstore-chain
  0.8.0  <- dig-download

The gate reads the LOCK, not the manifest range: `dig-constants = "0.4"` is
"satisfied" by a 0.4.0 lock forever, and only the lock says what compiles in.
It fails closed when crates.io cannot be read, because a gate that passes on
a network error is bypassable by causing one.

Placed before version resolution in the stable job so no tag exists to
deploy — releasing is the moment drift escapes the repo.

Verified against today's tree: reports all four versions and the staleness,
and exits 1.

NOT wired as a PR check yet, deliberately: dig-constants is stale today, so a
required check would block every open PR and the release it is meant to
protect. Promote it once #2072 lands.

Refs #2072

Co-Authored-By: Claude <noreply@anthropic.com>
@MichaelTaylor3d
MichaelTaylor3d force-pushed the ci/dig-constants-release-gate branch from 8fb2870 to d4ceb66 Compare August 3, 2026 23:16
@MichaelTaylor3d

Copy link
Copy Markdown
Contributor Author

Holding this PR deliberately — the gate is correct, and merging it now would freeze dig-node releases.

I ran the gate's own logic against origin/main's Cargo.lock. It fails, and it is right to:

dig-clvm         0.1.1    -> dig-constants 0.1.0
dig-download     0.15.0   -> dig-constants 0.8.0
dig-gossip       0.19.0   -> dig-constants 0.4.0
dig-nat          0.18.0   -> dig-constants 0.5.1
digstore-chain   0.19.2   -> dig-constants 0.5.1
dig-node-core    0.41.1   -> dig-constants 0.4.0
dig-node-service 0.94.0   -> dig-constants 0.4.0

Four distinct dig-constants versions linked into one binary against a published 0.9.0 — the exact duplication the script's header comment calls out as the dangerous case a version-bump review never catches. So the gate works.

But only two of those seven rows are dig-node's own crates. The rest live in other repos and must bump and publish first (release-first, §4.1), and every 0.x minor between them is semver-BREAKING — dig-clvm alone is eight breaking minors behind. That cascade is scoped on dig_ecosystem#2072.

Until it lands, this gate refuses every stable dig-node tag. dig-node shipped two emergency releases tonight — v0.93.9 to restore *.on.dig.net, v0.94.0 to fix the peer listener never binding — and a fail-closed release gate would have blocked both.

Sequencing: #2072 first, this second. Recorded as a hard dependency on that ticket. Nothing wrong with the PR; it is waiting on the world it is checking.

One thing worth adding while it waits, since it makes the gate safer to land: consider whether the first release after this merges should print the offending consumer list (cargo tree -i dig-constants) directly in the failure output. The current message tells you to run it; printing it turns a blocked release into a one-glance diagnosis.

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