release: promote develop → main (v0.16.1) - #1223
Merged
Merged
Conversation
chore: sync main → develop after v0.16.0
The spec's path table is hand-maintained in specBuilder.ts while the router is mounted in bootstrap.ts, and the two drifted. `const prefix = "/api"` landed in #23; #101 then cut the router over to `/api/v1` without touching the builder. Every path the spec has published since has been missing the version segment — including on the NyxID service page, which renders this spec as ornn-api's public contract. An agent developer following it calls /api/skills and gets nothing. CONVENTIONS.md §3 makes `/api/v1/` normative, so the spec was also contradicting its own contract doc. The contract tests pinned the wrong prefix rather than catching the drift, so they move with the fix. Adds a static guard asserting every declared path starts with `/api/v1/` — cheap, and needs no booted app. A stronger route-reflection guard follows in a later commit.
`servers` was pinned to `http://localhost:3802` and `info.version` to a
frozen `"2.0.0"` while the package sits at 0.16.0. Anyone reading the
published spec — NyxID renders it on the ornn-api service page — got a
base URL no client can reach and no way to tell which build they were
looking at.
`buildSpec` now takes both values from the caller. The server URL reuses
the existing ORNN_API_BASE_URL rather than introducing a second var:
ornn-web already reads it to reach the API, and two names for one fact
is precisely how the spec drifted from the router to begin with. Unset
falls back to `http://localhost:${PORT}`, so local dev and the test
harness need no configuration.
Deliberately NOT ORNN_PUBLIC_ORIGIN — that is the *web* origin, and
ornn-web/nginx.conf.template carries no proxy_pass, so the SPA host
never serves the API. In production the correct value is NyxID's proxy
base, which is what deployment/.env.sample.ornn already documents.
With the last URL literal gone from the module, `openapi/` no longer
needs its hardcode-sweep exemption, so the sweep now covers it.
…1213) The spec declared eight admin operations across four paths — list / create / update / delete for categories and tags. None of them exist. There is no categories or tags domain under ornn-api/src/domains, and no router anywhere registers those paths; grepping the booted route table returns nothing. They are leftovers from a surface that was removed without touching the spec builder. For an agent-facing product this is worse than an undocumented endpoint: a documented endpoint that 404s teaches the caller our contract is not trustworthy. The five Zod schemas that fed them (categorySchema, tagSchema, and the three body schemas) had no other consumer, so they go too. successResponseSchema stays — skillDeletePath still uses it. Removing the last "Admin"-tagged operations also empties that tag, so the tag declaration goes with them.
The three defects this PR fixes — wrong prefix, phantom admin paths, and the spec advertising URLs nobody can call — are one failure repeated: the spec claimed something the router does not serve. The existing contract tests could not catch any of them because they only inspect the spec against itself, and they had in fact frozen the wrong prefix into their own assertions. This boots the real app via the integration harness and checks each documented path+method against Hono's live route table. Verified it fails on the original bug: restoring `prefix = "/api"` reports all 15 operations as missing. Direction is deliberate. It asserts documented ⇒ registered (no phantom endpoints). The converse, registered ⇒ documented, is the coverage sweep in #1214 and would fail today on ~90 undocumented routes. `app.routes` lists one entry per handler in a chain, so entries are deduped and `ALL` (middleware mounts, not endpoints) is filtered out. The teardown carries an explicit 30s timeout. The seven existing integration files omit it, inherit bun's 5s default, and flake when mongo.stop() runs long — that's #1215, pre-existing and reproducible on develop. This file does not add to it.
The ornn-api suite failed roughly one run in three, on develop, with no diff applied: `(fail) (unnamed) [5001ms] — a beforeEach/afterEach hook timed out` plus `killed 2 dangling processes`. Two failures, always the same shape, always a different total test count. Root cause is scripts/migrate-quota-to-buckets.test.ts:17. It is the first file in the run to touch Mongo, so its `beforeAll` is the one that pays for downloading and unpacking the ~76 MB mongod binary on a cold cache — and it declares no timeout, so it inherits bun's 5s default. When the hook is killed, `db` is left undefined and the file's `beforeEach` fails on every test after it; that second-order failure is what the message actually names, which is why the reported hook is not the one at fault. The orphaned process is the dangling-process line. tests/integration/* already pass 30_000 to `beforeAll` for exactly this reason. This file was never given the same treatment. Teardowns get explicit timeouts too. They were not the trigger, but every one of them stops a real mongod under the same 5s default, so they are one slow shutdown away from the identical failure. The rule is documented on `Harness.cleanup` so the next harness consumer doesn't rediscover it. Verified: six consecutive full-suite runs, deterministic 2129 pass / 0 fail. Before the fix, four of five runs were red.
The `audit` job has been failing on every PR, including ones that touch
no dependency at all — the advisories are newly published against the
pinned tree, so `bun audit --audit-level=high` was red on develop itself.
Four override bumps clear seven of the eight:
postcss ^8.5.10 → ^8.5.18 (advisory <=8.5.17, via vite)
undici ^7.28.0 → ^7.29.0 (advisory <7.29.0, via jsdom)
brace-expansion added ^5.0.8 (advisory >=4.0.0 <5.0.8, via
eslint + typescript-eslint; 3
advisories collapse here)
js-yaml added ^4.3.0 (advisory >=4.0.0 <4.3.0, via
@changesets/cli)
postcss and undici already had overrides — they were simply pinned below
the fixed versions. None of these four ship in a runtime image; they are
build-, test-, and release-tooling only.
brace-expansion and js-yaml are forced across major/minor lines, so the
consumers were re-verified rather than assumed: lint, typecheck, web
build, and `changeset status` all pass, and the full test suite is
unchanged at 2129 pass / 0 fail.
The eighth advisory is react-router and is handled separately.
GHSA-qwww-vcr4-c8h2 ("RSC Mode CSRF Bypass") covers react-router >=7.12.0 <8.3.0. It is the last advisory keeping the audit job red, and it is not reachable in this codebase: - RSC mode requires the `@react-router/*` server packages. None are in bun.lock. - ornn-web is a static Vite SPA — `vite build`, no SSR target. - The router is built with createBrowserRouter + RouterProvider (ornn-web/src/App.tsx:258), so the vulnerable server-action path is never constructed. Fixing it properly is not a version bump. react-router 8.3.0 is the fixed release, but react-router-dom was frozen at 7.x and not carried forward, so adopting 8.x means migrating every `react-router-dom` import across the SPA. That is real regression surface and does not belong in a PR landing immediately before a release — tracked as #1219. Ignored with the reasoning inline, following the existing lodash-es precedent (#385) so the next reader can re-evaluate rather than trust a bare GHSA id. Removing the ignore is a checklist item on #1219. Audit now exits 0.
fix(api): correct every URL published in the OpenAPI spec
Step 0 of the release flow. check-release-notes.yml gates the develop → main promotion PR on a dated file existing with all three sections and no `(write here)` placeholder left. This release carries one pending changeset (patch), so it cuts v0.16.1. Its user-facing content is the OpenAPI contract fix: the published spec had the wrong path prefix, a localhost server URL, a frozen version, and four documented endpoints that did not exist. For an agent-facing API that document is the first thing a caller reads, so all three Fixed / Changed bullets are about it. The remaining work in the release — the test-suite flake and the dependency advisories — is developer-facing only, so it collapses into the technical-bucket bullets per the template's style rules. Empty changeset: docs-only, no package change.
…60806 docs: release notes for the next release
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 1 of the release flow in CLAUDE.md. Promotes
developtomain, which arms thechangeset-release.ymlstate machine: on the resultingmainpush it sees pending changesets and opens therelease/v0.16.1 → mainbump PR.Contents
Two pending changesets — one patch, one empty (docs) — so this cuts v0.16.1 from 0.16.0. Nine non-merge commits since the last release, all from one line of work:
/api/v1/openapi.jsonwas wrong. Paths sat under/api/*while the router has served/api/v1/*since #101;servers[0].urlwas hardcoded tohttp://localhost:3802;info.versionwas frozen at2.0.0; four/admin/{categories,tags}paths documented eight operations that exist nowhere in the codebase.auditjob was red on every PR from 8 high advisories in the pinned tree.Why this one matters
Ornn is an agent-facing API, and
/api/v1/openapi.jsonis the contract an agent developer reads before writing a single call — NyxID renders it directly on the ornn-api service page. Every URL in it was unusable. #1213 also adds a contract test that boots the app and checks each documented path against Hono's live route table, so a spec entry naming a route the API does not serve now fails CI rather than shipping.Release notes
.github/release-notes-20260806.mdis in place and thecheck-release-notesgate should pass on this PR.After merge
changeset-release.ymlopensrelease/v0.16.1 → main— review, Squash and merge.v0.16.1, publishes the GitHub Release using the dated notes file, and openssync/post-release-v0.16.1 → develop, auto-merged as a merge commit (never squash — a squash orphans the bump commit and later promotions show a phantom version bump).Follow-ups deliberately not in this release: #1214 (OpenAPI covers ~13% of the surface), #1216 (docker-compose
ORNN_API_BASE_URLhas a stray/api/v1suffix), #1219 (react-router 8 migration to drop the audit ignore).