Skip to content

fix(jsonapi)!: server error codes never collide with store variants - #208

Merged
sksizer merged 5 commits into
mainfrom
fix/pre090-release-prep
Oct 5, 2026
Merged

sksizer merged 5 commits into
mainfrom
fix/pre090-release-prep

Conversation

@sksizer

@sksizer sksizer commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Release prep for 0.9.0, from the post-merge audit of the M4 PRs: a changelog bug, an error-code collision, and the gaps in the 0.9 migration docs.

What changed

Changelog keeps every commit (cliff.toml, RELEASE.md)

The commit preprocessor \n()also matched the blank line after the subject when a body paragraph opened with a backtick. The joined message no longer parsed as a conventional commit, and git-cliff dropped it. It is now([^\r\n])\r?\n() -> $1 $2, which joins only a backtick-led line that continues a non-empty line, with LF or CRLF endings.

Measured on the full history at the first push (543 commits, git cliff --context):

preprocessor commits kept distinct ids footer entries
new 166 166 87
none 166 166 90
old 152 152 80
  • The new config keeps exactly the set the no-preprocessor run keeps. The old one dropped 14 commits, among them 71d76ce (fix(servers)!).
  • The no-preprocessor run has more footer entries because it cuts some footers in two.
  • The single BREAKING CHANGE: footer of feat(servers)!: custom ops, junction ops, entity-less CRUD and event frames speak JSON:API #201 renders whole: one entry, and its text matches the commit message.
  • In a scratch repo, a commit whose body opens with a backtick is kept with the new config and dropped with the old one. A footer whose wrapped line starts with a backtick stays whole.
  • After the CRLF change, at 3429f44 (168 commits), the new, LF-only and no-preprocessor configs keep the same 168 commits. In CRLF commits the new pattern joins a backtick-led continuation with a plain space; the LF-only pattern left a stray \r, and no preprocessor split the footer.

RELEASE.md now says the trailer hazard is git-cliff's footer parser, not git. That parser treats any continuation line starting with token: or token # as a new trailer. A backtick-led continuation line is joined automatically, and a blank line before a backtick-led paragraph is safe.

JSON:API error codes never collide with store variants

An entity named Relationship or RelatedResource could not build. Its required AppError::{Entity}NotFound has the code relationship_not_found or related_resource_not_found, and those are codes the server raises itself. check_codes refused the clash even in builds with no HTTP server.

  • The two codes are renamed: relationship_not_found -> no_such_relationship and related_resource_not_found -> no_such_related_resource. The ErrorCode variants are renamed to match, and the helper relationship_not_found() is now no_such_relationship().
  • No ontogen code ends in a store suffix (_not_found, _id_required, _already_exists, _parent_required). A unit test pins this over ErrorCode::ALL, using the suffix table status_for already uses (now STORE_SUFFIXES).
  • ErrorCode::ALL is a &'static [ErrorCode], so adding a code no longer changes its type.
  • check_codes runs only when an HttpAxum generator is configured. IPC-only and MCP-only builds are not refused.
  • Docs updated: the wire contract (§8, §9, §13.2, §13.3 table, and the §13.4 clash rule, which now states the suffix invariant and the HTTP gate), the server-transports and relationships guides, and the upgrading page.
  • No *-wire.mdx page shows either code, so none needed re-capturing.

Upgrading page

  • New "OKF vaults" section. It covers every 0.8.0 -> 0.9.0 OKF break from feat(markdown)!: vaults are OKF 0.2 bundles by default #194 and feat(markdown)!: OKF index files and provenance stamps, configured once at build time #196. Each item was checked against the code and against ontogen-v0.8.0:
    • the type_name default flip;
    • type stamped on create and on every real update, and the Flat filtering by type (untyped records are listed by every entity until stamped);
    • the reserved type key is a build error, and other OKF keys warn;
    • gen_markdown_io(&SchemaOutput, …);
    • okf: OkfOptions on MarkdownIoConfig/MarkdownIoOptions (neither implements Default);
    • the MarkdownIoOutput field removals;
    • gen_frontmatter::generate removed;
    • index.md/log.md not listed;
    • opt-in index files and generated stamps;
    • open_vault/with_okf versus a hand-built VaultHandle::new;
    • FieldDef.frontmatter_name.
  • "Where to start" list in the intro lists every top-level section in page order, one line each.
  • ontogen-jsonapi changes moved. The paragraph listing them sat inside a build-configuration subsection. ontogen-jsonapi 0.1.0 was published (tag ontogen-jsonapi-v0.1.0, 2026-10-03), so it is not deleted. It moves into its own subsection, "Code that calls ontogen-jsonapi 0.1 directly", which also records this PR's ErrorCode changes.
  • List order. "ordered by id" now reads "unless the request gives sort".
  • TypeScript Transport exceptions. The page said "three exceptions". Diffing generate_transport_interface against ontogen-v0.8.0 gives six, and the page now lists them at the top of the TypeScript section, which is split into HTTP, IPC and bindings paragraphs:
    • no paginated xCount();
    • junction add/remove declared Promise<null>;
    • a lone list_X takes no page;
    • a required query when the *Query struct has a required field;
    • a bare filter whose type name contains Query/Input keeps its own name;
    • options, which points to Sorting.
  • Link query order. It is stated once, under Pagination, and the other places link to it.
  • Ids ., .. and "". The page said such rows "must be renamed before you upgrade", which was unsupported. They stay reachable through the store, API, IPC and MCP. Over HTTP, "" has no route, and ./.. are reachable only from a client that does not normalise the path. Both were probed and are the same as in 0.8. A vault never could hold them.
  • {Entity}IdRequired is needed for markdown entities and for SeaORM entities under Provided/SlugFromField, not for every entity. The same qualifier is applied in the server-transports and store-layer guides, the adding-a-new-entity cookbook and contract §13.4.
  • The u32 migration SQL uses <table>/<column> placeholders. The old example column (workout_set.reps) is an i32, and no example has a u32 field.
  • Smaller fixes. The "Ops the generator now refuses" scope sentence is corrected. The Markdown-store API bullet no longer lists EntityRecords::create, which did not exist in 0.8.0, as changed.

Planning docs and contract drift

Breaking changes

  • ontogen 0.8.0 consumers. None. The renamed codes were never served by a released ontogen.
  • ontogen-jsonapi 0.1.0 callers. For anyone using the crate directly, the ErrorCode variant renames and the type of ALL are breaks. The crate goes to 0.2.0 in the release PR. Hence the ! and one footer below; the upgrading page's "Code that calls ontogen-jsonapi 0.1 directly" has the migration.

Snapshots and examples

  • servers_jsonapi_ops_http, servers_jsonapi_ops_scoped_http and servers_jsonapi_resources_http change only in the error import line and the five no_such_relationship(...) calls.
  • These were regenerated: markdown-pilot's two HTTP generated.rs files, and the HTTP generated.rs of iron-log, iron-log-md, notes-kb and tasks-tracker.

Also: src/lib.rs rustdoc no longer says open_vault or MarkdownIoOutput carry the id strategy. Contract §13.4 states the suffix rule as one every new code must keep, enforced by no_ontogen_code_ends_in_a_store_suffix, and notes a new code can still clash with a consumer's own non-store variant. The OKF section says what a null or empty type does: null is untyped, "" is a string other than the entity's.

Tests added

Each was checked to fail before the fix.

  • servers::error_map::tests::no_ontogen_code_ends_in_a_store_suffix
  • servers::error_map::tests::store_variants_of_relationship_named_entities_pass_the_code_check
  • builder_checks_app_error_codes_only_for_an_http_server (tests/builder.rs)
  • builder_http_code_check_accepts_store_variants_of_relationship_named_entities (tests/builder.rs; it generates no routes, so it proves the code check only)

Not in this PR

Verification

  • just full-check passes.
  • just regen-examples leaves no drift.
  • upgrading.mdx and the two guides compile with @mdx-js/mdx, and every in-page anchor resolves.
  • The git-cliff measurements are as above.

Squash commit message

fix(jsonapi)!: server error codes never collide with store variants

An entity named Relationship or RelatedResource could not build, because
its required NotFound variant had the code of one the JSON:API server
raises itself. Those two codes are now no_such_relationship and
no_such_related_resource. A test pins that no ontogen code ends in a
store suffix, the clash check runs only when the build generates the
HTTP server, and ErrorCode::ALL is a slice.

The cliff.toml preprocessor joins a backtick-led line only onto a
non-empty line, so a commit whose body opens with a backtick is no
longer dropped from the changelog; RELEASE.md names the hazard.

The upgrading page gains an OKF vaults section covering every 0.8.0
break from the OKF epic, a where-to-start list, a subsection for
callers of ontogen-jsonapi 0.1, and corrected statements on list
order, the Transport changes, link query order, odd ids, IdRequired
and the u32 migration. Epic E0004's acceptance criteria record what met
them and the Transport deviations, the roadmap states the deviation,
and ADR 0004, ADR 0006 and wire contract §16 drift is fixed.

BREAKING CHANGE: ontogen-jsonapi renames the ErrorCode variants
RelatedResourceNotFound and RelationshipNotFound to
NoSuchRelatedResource and NoSuchRelationship, whose codes are
no_such_related_resource and no_such_relationship, and ErrorCode::ALL
is a &'static [ErrorCode].

…ktick

The cliff.toml preprocessor joined any backtick-led line onto the line
before it, including the blank line after the subject, so such a commit
no longer parsed and git-cliff dropped it. It now joins only a line that
continues a non-empty one. RELEASE.md names git-cliff's footer parser as
the source of the trailer hazard.
Each acceptance criterion names the PRs that met it. The Transport
criterion records its deviations: a paginated module's xCount() is gone,
junction add and remove resolve Promise<null>, and a lone list_X takes no
page. The roadmap's M4 note states the deviation, ADR 0004 points at the
epic for decisions 10-12 and at ADR 0006 for the schema argument, and
ADR 0006 no longer credits #197.
An entity named Relationship or RelatedResource could not build: its
required NotFound variant had the code of one the server raises itself.
The codes are now no_such_relationship and no_such_related_resource, a
test pins that no ontogen code ends in a store suffix, and the code
clash check runs only when the build generates the HTTP server.
ErrorCode::ALL is a slice. The wire contract's §16 EventSource reason and
id-rule row are corrected.

BREAKING CHANGE: ontogen-jsonapi renames ErrorCode::RelatedResourceNotFound
and ErrorCode::RelationshipNotFound to NoSuchRelatedResource and
NoSuchRelationship (codes no_such_related_resource and
no_such_relationship), and ErrorCode::ALL is a &'static [ErrorCode].
…order

An OKF vaults section lists every 0.8.0 break from the OKF epic. A
where-to-start list orders the sections, the ontogen-jsonapi 0.1 changes
get their own subsection, and the page's statements on list order, the
Transport changes, link query order, odd ids, IdRequired and the u32
migration match the code.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Deploying ontogen with  Cloudflare Pages  Cloudflare Pages

Latest commit: d27db20
Status: ✅  Deploy successful!
Preview URL: https://9cf608c8.ontogen.pages.dev
Branch Preview URL: https://fix-pre090-release-prep.ontogen.pages.dev

View logs

The epic and roadmap list all five Transport deviations, IdRequired is
scoped the same way in every guide and the contract, the upgrading page
lists its sections in page order and splits the TypeScript section by
surface, and src/lib.rs no longer says open_vault or MarkdownIoOutput
carry the id strategy. The cliff.toml preprocessor also joins CRLF
continuation lines.
@sksizer
sksizer merged commit ec5cae7 into main Oct 5, 2026
6 checks passed
@sksizer
sksizer deleted the fix/pre090-release-prep branch October 5, 2026 05:23
@github-actions github-actions Bot mentioned this pull request Oct 5, 2026
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