diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e66681c305..9f8344aa03 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -164,7 +164,10 @@ produces `1.0.0-rc.1.2`. A minor or major change advances the candidate number: `1.0.0-rc.1.2` becomes `1.0.0-rc.2`. Packages already on stable 1.x versions, including `@tanstack/query-db-collection` and `@tanstack/offline-transactions`, continue to use normal semantic versioning -and publish under npm's `latest` tag. +and publish under npm's `latest` tag. Release candidates also publish under +`latest`, per the maintainer's 2026-10-29 decision. Existing versions are not +republished to move a tag: use `npm dist-tag add @ latest`. +This preserves any existing `rc` alias. ## Pull requests diff --git a/docs/contributing/oracle-coverage.md b/docs/contributing/oracle-coverage.md index afa469b5b0..a6616dd4df 100644 --- a/docs/contributing/oracle-coverage.md +++ b/docs/contributing/oracle-coverage.md @@ -1,5 +1,22 @@ # Oracle coverage and closeout +## RC npm tag policy, 2026-10-29 + +The maintainer directed RC versions to npm's `latest` tag on 2026-10-29. +`CONTRIBUTING.md` records this policy. The release-history model and command/HTTP +receivers now expect `latest` for candidate and stable uploads. Exact-version +membership still decides whether an upload is needed; an existing version is +never republished to move a tag. Existing `rc` aliases are preserved by the +separate `npm dist-tag add @ latest` operation. + +Historical campaign records below retain the former `rc`-only authority and +its P01 findings. They are not current tag-policy evidence. The existing +histories, comparisons, reach declarations, and run budgets remain intact. +The maintainer explicitly stopped local tests during this release. No RED, +GREEN, or mutant campaign was run for this policy change; execution evidence +is pending CI. The command/HTTP owners do not cover manual tag promotion, +production npm credentials, or Actions authentication. + ## RC scope partition, 2026-10-29 The [deferred oracle record](oracle-reviews/2026-10-29-pr-2171-deferred-oracles.md) diff --git a/scripts/publish-history-oracle.property.test.js b/scripts/publish-history-oracle.property.test.js index 538ae0755d..db64af9731 100644 --- a/scripts/publish-history-oracle.property.test.js +++ b/scripts/publish-history-oracle.property.test.js @@ -1,7 +1,7 @@ /** - * Candidates must reach rc and stable versions must reach latest, independent - * of registry history. CONTRIBUTING.md supplies this policy; stable minors are - * the maintainer's deliberate policy. The shared model states the independent + * Candidates and stable versions must reach latest, independent of registry + * history (maintainer decision 2026-10-29, recorded in CONTRIBUTING.md). + * Stable minors are the maintainer's deliberate policy. The shared model states the independent * version/tag law. A registry ledger is controlled input, not a tag classifier. * * The receiver invokes production publishDuringRc with its default command. @@ -150,7 +150,7 @@ test.each(['duplicate', 'omission', 'tag', 'version', 'registry', 'access'])( 'release publish judgment rejects wrong %s observation', (fault) => { const expected = [ - { name: packageNames.db, version: '1.0.0-rc.1.10', tag: 'rc' }, + { name: packageNames.db, version: '1.0.0-rc.1.10', tag: 'latest' }, ] const correct = [ { @@ -168,7 +168,7 @@ test.each(['duplicate', 'omission', 'tag', 'version', 'registry', 'access'])( else wrong[0][fault] = fault === 'tag' - ? 'latest' + ? 'rc' : fault === 'version' ? '1.0.0-rc.1.9' : fault === 'registry' diff --git a/scripts/publish-http-oracle.property.test.js b/scripts/publish-http-oracle.property.test.js index bf1569aefe..e4756a57ea 100644 --- a/scripts/publish-http-oracle.property.test.js +++ b/scripts/publish-http-oracle.property.test.js @@ -1,6 +1,6 @@ /** - * Candidate releases reach rc; stable releases reach latest exactly once. - * Authority: CONTRIBUTING.md Changesets/Releases and the accepted RC policy. + * Candidate and stable releases reach latest exactly once. + * Authority: CONTRIBUTING.md Changesets/Releases, maintainer decision 2026-10-29. * The existing release ledger supplies the independent version/tag judgment. * This receiver crosses the real npm11/pnpm11/Changesets HTTP boundary, with * the default production publish command and real package-manager archives. @@ -9,8 +9,9 @@ * The bounded shared grammar retains the original metadata/failure histories * and varies exact-version presence independently of tags. Current candidates * can have only latest, no tags, or rc pointing to an older present version. - * The exact wrong-tag aftermath keeps old rc alongside latest=current. A - * separate stable-phase neighbor removes stable latest while versions remain. + * A historical old-policy wrong-tag aftermath keeps old rc alongside + * latest=current. A separate stable-phase neighbor removes stable latest + * while versions remain. * Missing targets also have a no-tags neighbor. Two different candidate * versions vary which package is already current and reverse their assignment. * A later-candidate fault follows an actual successful candidate upload, in diff --git a/scripts/publish-packages.mjs b/scripts/publish-packages.mjs index 80e8bc6af2..1eb1cf785d 100644 --- a/scripts/publish-packages.mjs +++ b/scripts/publish-packages.mjs @@ -57,7 +57,9 @@ async function publishWithHiddenPackages( /** * Publish stable versions first, then candidates, grouped by exact version. * npm reads that exact version even when dist-tags are missing or stale. - * Explicit upload tags are independent of the metadata selector. + * Uploads use latest under the maintainer's RC policy (CONTRIBUTING.md), + * independently of the exact-version metadata selector. Existing versions + * are skipped; promoting their tags requires a separate npm dist-tag command. */ export async function publishDuringRc( rootDirectory = root, @@ -91,7 +93,7 @@ export async function publishDuringRc( publicPackages.filter( ({ packageJson }) => packageJson.version !== version, ), - { version, tag: stableVersion.test(version) ? 'latest' : 'rc' }, + { version, tag: 'latest' }, publishCommand, ) } diff --git a/scripts/publish-packages.test.mjs b/scripts/publish-packages.test.mjs index a87713a1e3..adc9906d47 100644 --- a/scripts/publish-packages.test.mjs +++ b/scripts/publish-packages.test.mjs @@ -49,7 +49,7 @@ function packageState(root) { ) } -test('RC publishing gives candidate and stable packages their own npm tags', async (t) => { +test('RC publishing uses latest while isolating candidate and stable versions', async (t) => { const root = createWorkspace() t.after(() => rmSync(root, { recursive: true, force: true })) const before = packageState(root) @@ -82,7 +82,7 @@ test('RC publishing gives candidate and stable packages their own npm tags', asy publicNames: ['@tanstack/db'], preMode: false, version: '1.0.0-rc.2', - tag: 'rc', + tag: 'latest', }, ]) assert.deepEqual(packageState(root), before) @@ -98,7 +98,8 @@ test('failed candidate publishing restores package manifests and prerelease stat await assert.rejects( publishDuringRc(root, (_, publication) => { phase++ - if (publication.tag === 'rc') throw new Error('publish failed') + if (publication.version.startsWith('1.0.0-rc.')) + throw new Error('publish failed') }), /publish failed/, ) diff --git a/scripts/release-history-oracle.js b/scripts/release-history-oracle.js index 154951dda7..837d0a9209 100644 --- a/scripts/release-history-oracle.js +++ b/scripts/release-history-oracle.js @@ -2,7 +2,8 @@ * Release laws come from CONTRIBUTING.md's Changesets and Releases sections: * candidates start at 1.0.0-rc.1, patches extend the current candidate, and a * minor or major starts the next candidate. Stable packages use ordinary semver - * and latest; candidates use rc. Versioning consumes each changeset once. + * and latest. Candidates also use latest (maintainer decision 2026-10-29, + * recorded in CONTRIBUTING.md). Versioning consumes each changeset once. * Exit promotes candidates to 1.0.0 and applies only still-pending work. * * This independent model uses numeric tuples and an authored changeset ledger. @@ -318,11 +319,7 @@ export function expectedPublishes(manifests, registry) { .map((manifest) => ({ name: manifest.name, version: manifest.version, - tag: - manifest.name === packageNames.db || - manifest.name === packageNames.react - ? 'rc' - : 'latest', + tag: 'latest', })) }