diff --git a/.changeset/fix-compression-cutoff-beta18.md b/.changeset/fix-compression-cutoff-beta18.md new file mode 100644 index 0000000000..06ec1fbd15 --- /dev/null +++ b/.changeset/fix-compression-cutoff-beta18.md @@ -0,0 +1,5 @@ +--- +'@workflow/core': patch +--- + +Fix the payload-compression capability cutoff: gzip/zstd are gated on `5.0.0-beta.18` (the first published version containing the compression read path) instead of `5.0.0-beta.16`. The previous cutoff would let a producer write compressed payloads to a beta.16/beta.17 target that cannot decode them. diff --git a/packages/core/src/capabilities.ts b/packages/core/src/capabilities.ts index a1d7844bea..4ef6b5a78e 100644 --- a/packages/core/src/capabilities.ts +++ b/packages/core/src/capabilities.ts @@ -28,8 +28,8 @@ * Commit: 7618ac36 "Wire AES-GCM encryption into serialization layer (#1251)" * https://github.com/vercel/workflow/commit/7618ac36 * - `framedByteStreams` (wire-level chunk framing for byte streams): added in `5.0.0-beta.15` - * - `gzip` (gzip payload compression): added in `5.0.0-beta.16` - * - `zstd` (zstd payload compression, preferred codec): added in `5.0.0-beta.16` + * - `gzip` (gzip payload compression): added in `5.0.0-beta.18` + * - `zstd` (zstd payload compression, preferred codec): added in `5.0.0-beta.18` * alongside gzip — they co-ship, so any run that can read one can read both. */ @@ -77,8 +77,8 @@ const FORMAT_VERSION_TABLE: ReadonlyArray<{ // compressed payloads to consumers that cannot decompress them; too-high // merely delays the optimization (safe). gzip and zstd ship together, so // they share a min version — a run that can read one can read both. - { format: SerializationFormat.GZIP, minVersion: '5.0.0-beta.16' }, - { format: SerializationFormat.ZSTD, minVersion: '5.0.0-beta.16' }, + { format: SerializationFormat.GZIP, minVersion: '5.0.0-beta.18' }, + { format: SerializationFormat.ZSTD, minVersion: '5.0.0-beta.18' }, // Future entries: // { format: SerializationFormat.CBOR, minVersion: '5.x.y' }, // { format: SerializationFormat.ENCRYPTED_V2, minVersion: '5.x.y' }, diff --git a/packages/core/src/serialization/compression.test.ts b/packages/core/src/serialization/compression.test.ts index 2d42ffa6c7..355183b7ef 100644 --- a/packages/core/src/serialization/compression.test.ts +++ b/packages/core/src/serialization/compression.test.ts @@ -441,14 +441,29 @@ describe('run capabilities for compression codecs', () => { SerializationFormat.GZIP, SerializationFormat.ZSTD, ] as const) { - it(`supports ${fmt} for core versions >= 5.0.0-beta.16`, () => { - expect( - getRunCapabilities('5.0.0-beta.16').supportedFormats.has(fmt) - ).toBe(true); + it(`supports ${fmt} for core versions >= 5.0.0-beta.18`, () => { + for (const version of [ + '5.0.0-beta.18', + '5.0.0-beta.19', + '5.0.0', + '6.0.0', + ]) + expect(getRunCapabilities(version).supportedFormats.has(fmt)).toBe( + true + ); }); it(`does not support ${fmt} for older core versions`, () => { - for (const version of ['5.0.0-beta.15', '4.2.1', '4.0.0']) { + // beta.16 and beta.17 were published before compression shipped, so a + // producer must treat those targets as compression-incapable — writing + // a codec they cannot decode is the silent-corruption failure mode. + for (const version of [ + '5.0.0-beta.17', + '5.0.0-beta.16', + '5.0.0-beta.15', + '4.2.1', + '4.0.0', + ]) { expect(getRunCapabilities(version).supportedFormats.has(fmt)).toBe( false );