Skip to content

chore: enforce release readiness - #35

Draft
leoafarias wants to merge 4 commits into
agent/rockets-firestore-parityfrom
agent/rockets-release-readiness
Draft

chore: enforce release readiness#35
leoafarias wants to merge 4 commits into
agent/rockets-firestore-parityfrom
agent/rockets-release-readiness

Conversation

@leoafarias

@leoafarias leoafarias commented Aug 8, 2026

Copy link
Copy Markdown
Member

Summary

Turn the 1.0 preview requirements into a gate that actually runs, and fix what running it exposed.

Before this PR, release:check proved the repository compiles and passes its own tests. It proved nothing about what gets published or consumed. Every one of the following was true and undetected:

Gap Consequence
No check that files / main / types / exports / bin resolve to real built artifacts A package could publish a manifest pointing at paths absent from the tarball
No check that bin entries avoid ts-node A published CLI could require a devDependency the consumer doesn't have
Firestore parity asserted only against its own in-memory double #37's semantics were unverified against a real Firestore
Examples built and tested by hand, never by CI The three sample apps could drift from the packages they demonstrate
Vitest configs were .ts Node's native config loader cannot read them; only the bundled loader worked

After this PR, release:check runs: build → artifact verification (60 targets)dry-run pack → typecheck → lint → unit → package e2e → real Firestore emulatorbuild all examplese2e all examples.

Stack: based on #37 (agent/rockets-firestore-parity), the top of the four-PR stack. Review this diff against agent/rockets-firestore-parity, not main.


What changed and why

1. Package artifacts are verified against the built tree

scripts/verify-package-artifacts.mjs walks every public @concepta/* package and fails on: a files / main / types / exports / bin target that doesn't exist, any target pointing into src/, a missing main or types, publishConfig.access that isn't public, engines.node below 20, and any bin script that pulls in ts-node/register or reaches into ../src/. Currently 60 targets across 6 packages. release:packages runs it, then dry-run packs every publishable workspace.

This is why engines.node >= 20 and the packaging fields are normalized in #34, #36, and #37 — those PRs carry the fixes; this PR adds the check that keeps them fixed.

2. Firestore parity runs against a real Firestore

firestore-backend.emulator-spec.ts seeds four documents covering missing / null / number / string shapes, runs the same query through both the Admin backend and the in-memory backend, and asserts identical result ids. Wired through firebase.json, firestore.rules, vitest.firestore.config.mts, and a test:firestore-emulator script that runs the suite inside firebase emulators:exec. The suite is excluded from the package tsconfig so it never enters the published archive.

This is the verification for #37, which lands two PRs below. See Review focus (2) for exactly how much of #37 it covers.

3. Vitest configs load natively

vitest.config.ts.mts, vitest.shared.ts.mts, and the three example e2e configs likewise. test:config-native (vitest list --configLoader native) asserts it, and runs on the Node 22 CI job — the loader path that would otherwise only break for a consumer.

4. Examples are part of the gate, and stop shadowing the packages

samples:build and samples:test:e2e now include sample-code-review, and both run inside release:check. The three example-local define-typeorm-repository.ts copies are deleted in favor of the real defineTypeOrmRepository that #34 moved into @concepta/rockets-repository-typeorm — so the examples now demonstrate the shipped API instead of a private fork of it.

5. CI split across two Node versions

A new release-readiness workflow runs the full gate on Node 20 with Java 21 and a cached Firestore emulator. The existing ci-pr-test job stays on Node 22 and picks up the native config check. Node 20 is the floor the packages declare; Node 22 is where the native loader is exercised.

6. Documentation and metadata for the final public surface

README.md and CONFIGURATION.md rewritten around createServer / defineAuthAdapter / defineTypeOrmRepository / defineRocketsAuth; MIGRATION-SUMMARY.md deleted; the stale generated swagger/swagger.json and the root generate-swagger script removed (the generator itself is removed in #34 and #36); the broad root path-to-regexp resolution dropped, which the Firebase CLI requires in order to keep its Express-compatible dependency.


Breaking changes & compatibility

Change Migration
Public packages require Node.js 20+ Upgrade the runtime; engines is now enforced by the release gate.
Root path-to-regexp resolution removed Dependents resolve their own; required for firebase-tools to function.
yarn generate-swagger and swagger/swagger.json removed Generate OpenAPI from your own app, which owns the complete Nest graph and document settings.
Examples import defineTypeOrmRepository from @concepta/rockets-repository-typeorm Copy the import, delete any app-local fork of the helper.

No package version bump is included — versioning stays a separate release decision.


Review focus

Ranked by blast radius. The first two are decisions rather than defects.

1. firebase-tools is a very large root devDependency — package.json, yarn.lock

firebase-tools@15.15.0 adds 398 packages and ~3,250 lockfile lines, which is the bulk of this diff, to support one three-assertion parity suite. It also installs for every contributor who runs yarn install, not only for the job that needs it. Alternatives worth weighing before merge: install it only in the release-readiness CI job, or isolate it in a dedicated non-published workspace. Flagging it explicitly so the cost is accepted rather than absorbed silently.

2. The emulator suite covers three of #37's claims, not all of them

Verified against real Firestore: explicit-null vs. missing nested fields, cross-type range exclusion, and nested ordering with recursive timestamp normalization. Not covered by an emulator assertion: document-ID intersection inside AND, branch filters applying on the ID-selected path (the widening bug #37 fixes), duplicate-create rejection, and the nin / between post-filter changes. Those remain in-memory-only. Worth deciding whether the gap is acceptable for 1.0 or whether the suite grows before release.

3. Deleting swagger/swagger.json removes a documented source of truth — .claude/rules/editing-guidelines.md

That rule file still names packages/rockets-server-auth/swagger/swagger.json as "Public API surface for auth package". The artifact was stale — it documented removed /oauth/* routes and the old GET /recovery/passcode/{passcode}, and none of #36's four new recovery routes — so deleting it is right. But the rule needs to either point somewhere else or be removed; nothing in this stack updates it.

4. Neither workflow runs while the stack is stacked

ci-pr-test.yml and release-readiness.yml both trigger on pull_request: branches: ['main']. #36, #37, and #35 target their parent branches, so they currently report no checks — only #34 gets CI. This is intentional rather than broken: retargeting each PR to main immediately before merging is the documented merge process, and that is exactly when the gate should run. But it does mean GitHub shows no signal on this PR until it is retargeted — all gates below were run locally instead.

5. release:check is now long and serial

Build → artifacts → dry-run pack → typecheck → lint → unit → package e2e → emulator → build 3 examples → e2e 3 examples. Fine for a release gate, painful as an inner-loop command. The narrower scripts (test, test:e2e, release:packages) remain available individually.


Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring
  • Dependency update

Verification

Full release:check scope, run locally at this branch's tip after rebasing the stack onto the current #34 and #36 heads:

Gate Result
corepack yarn build pass
corepack yarn typecheck:spec pass
corepack yarn lint:all pass
corepack yarn release:packages 60 public package artifact targets verified, dry-run pack clean
corepack yarn test 69 files / 605 tests passed
corepack yarn test:e2e 33 files / 167 tests passed
corepack yarn test:firestore-emulator 1 file / 3 tests passed (Java 21, real emulator)
sample-server e2e 8 files / 194 tests passed
sample-server-auth e2e 2 files / 40 tests passed
sample-code-review e2e 8 passed, 1 skipped (skipped test needs an external integration)
corepack yarn install --immutable lockfile coherent after the rebase merge

Two verification notes, in the interest of not overstating the result:

  • One e2e run in three failed with two rotating victims (rockets-core.e2e-spec.ts and rockets-for-root-async.e2e-spec.ts). Both pass in isolation and the immediately following full run was clean at 33/33. This matches the environmental pattern documented at CHANGELOG.md under "Intermittent e2e failures". No assertion was weakened and no test was retried in-suite to hide it.

  • GitHub shows no checks on this PR for the reason in Review focus (4). The results above are local.

  • Build succeeds

  • Unit tests pass

  • E2E tests pass

  • Lint passes

Checklist

  • My code follows the existing patterns in the codebase
  • I have updated relevant documentation
  • I have added tests for new functionality

Scope boundaries with the stack

This is the top of the stack (#34#36#37#35). Content that logically belongs to a release-readiness PR but is deliberately not here, because an earlier PR already owns the file:

Item Owner
engines.node >= 20 and packaging-field fixes for rockets-core, rockets-server, rockets-repository-typeorm, rockets-adapter-firebase #34
Same for rockets-server-auth; removal of the rockets-auth-swagger bin and SWAGGER.md #36
Same for rockets-repository-firestore #37

The inverse also holds and is worth knowing while reviewing: this PR carries the verification for changes that land below it — the emulator contract proves #37, and the example rewrites exercise #34's createServer / defineAuthAdapter / defineTypeOrmRepository and #36's defineRocketsAuth contributions. Merging the stack out of order, or merging #37 alone, ships those changes without their proof.

@leoafarias
leoafarias force-pushed the agent/rockets-firestore-parity branch from 4b84dcd to 967b45b Compare August 8, 2026 23:53
@leoafarias
leoafarias force-pushed the agent/rockets-release-readiness branch from f8dcfce to bdb867e Compare August 8, 2026 23:53
@leoafarias
leoafarias force-pushed the agent/rockets-firestore-parity branch from 967b45b to 4c27233 Compare August 8, 2026 23:56
@leoafarias
leoafarias force-pushed the agent/rockets-release-readiness branch from bdb867e to 355efe1 Compare August 8, 2026 23:56
@leoafarias
leoafarias force-pushed the agent/rockets-firestore-parity branch from 4c27233 to 094e9e5 Compare August 9, 2026 16:14
@leoafarias
leoafarias force-pushed the agent/rockets-release-readiness branch from 355efe1 to 0414fe5 Compare August 9, 2026 16:14
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