Skip to content

release: promote develop → main (v0.16.1) - #1223

Merged
chronoai-shining merged 12 commits into
mainfrom
develop
Aug 6, 2026
Merged

release: promote develop → main (v0.16.1)#1223
chronoai-shining merged 12 commits into
mainfrom
develop

Conversation

@chronoai-shining

Copy link
Copy Markdown
Collaborator

Step 1 of the release flow in CLAUDE.md. Promotes develop to main, which arms the changeset-release.yml state machine: on the resulting main push it sees pending changesets and opens the release/v0.16.1 → main bump 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:

Issue What
#1213 Every URL published in /api/v1/openapi.json was wrong. Paths sat under /api/* while the router has served /api/v1/* since #101; servers[0].url was hardcoded to http://localhost:3802; info.version was frozen at 2.0.0; four /admin/{categories,tags} paths documented eight operations that exist nowhere in the codebase.
#1215 ornn-api suite flaked ~1 run in 3 — the first Mongo-booting file downloaded mongod inside a hook with no timeout, so it inherited bun's 5s default.
#1218 audit job was red on every PR from 8 high advisories in the pinned tree.
#1220 Curated release notes for this release.

Why this one matters

Ornn is an agent-facing API, and /api/v1/openapi.json is 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.md is in place and the check-release-notes gate should pass on this PR.

After merge

  1. changeset-release.yml opens release/v0.16.1 → main — review, Squash and merge.
  2. That push tags v0.16.1, publishes the GitHub Release using the dated notes file, and opens sync/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_URL has a stray /api/v1 suffix), #1219 (react-router 8 migration to drop the audit ignore).

chronoai-shining and others added 12 commits July 7, 2026 18:37
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
@chronoai-shining
chronoai-shining merged commit d309d9b into main Aug 6, 2026
21 checks passed
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