Conversation
Inside a Rust string literal a trailing `\` eats the newline *and every
leading space on the next line*. The registry template used `\`
continuations to splice in two optional chunks, so it was silently
losing the indentation on the two lines that followed them: every
entity's opening brace and its `fields:` key both landed in column 0
while their contents stayed indented.
export const adminEntities: AdminEntityConfig[] = [
{ <- wanted two spaces
key: 'exercise',
paginated: false,
fields: [ <- wanted four
{ key: 'id', ... }],
},
The optional chunks already carry their own trailing newline, so they
splice inline and the continuations are not needed at all. Dropping them
restores the indentation the template always intended, and a comment
records why `\` must not come back.
Output only; no field, flag or value changes. The registry tests assert
on content rather than layout and are unaffected.
The examples commit their generated trees so diffs are reviewable, but nothing regenerates them, so they had drifted a long way from what the pipeline actually emits. iron-log's lockfile was still pinning ontogen 0.3.1. What the rebuild brings in, none of it authored by hand: - `count_*` store methods and the `PaginatorTrait` import they need, from the pagination pushdown in #159 — never written back at the time. - The admin registry's indentation, from the fix in the previous commit. - Semicolons on the emitted TypeScript, from an earlier generator change; the committed files predate it. - A `sha2` dependency chain in notes-kb and tasks-tracker, and version bumps across every lockfile. All four examples build against the regenerated output. Doing this now means the next generator change shows a diff that is only that change, instead of one carrying two releases of backlog.
Deploying ontogen with
|
| Latest commit: |
f301590
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://0b46a1d4.ontogen.pages.dev |
| Branch Preview URL: | https://fix-iron-log-admin-registry.ontogen.pages.dev |
| }, | ||
| { key: 'notes', label: 'Notes', type: 'string', showInDetail: true, showInForm: true }, | ||
| ], | ||
| { key: 'id', label: 'Id', type: 'string', required: true, showInTable: true, showInDetail: true, showInForm: true, isId: true }, |
There was a problem hiding this comment.
These regenerated TS files break iron-log's own Prettier config. src-nuxt/.prettierrc sets semi: false and printWidth: 100, and .prettierignore doesn't exclude app/generated/ or app/admin/generated/. The previous committed files were Prettier-formatted (no semicolons, wrapped field objects), so the ; and >100-col lines here are the unformatted generator output — not "an earlier generator change the committed files predate" as the PR description says.
Failure: pnpm format:check / just ci fails, and the lefthook prettier --check {staged_files} pre-commit hook rejects any commit that stages these files. Running pnpm format then cargo build flips them back and forth forever. The same applies to app/generated/transport.ts and app/generated/types.ts.
| WorkoutSet, | ||
| WorkoutStats, | ||
| } from './types' | ||
| } from './types'; |
There was a problem hiding this comment.
Root cause is in examples/iron-log/src-tauri/build.rs, not the committed output. iron-log's ClientsConfig falls through to ts_formatter: TsFormatter::None, so build.rs writes unformatted TS into a tree that Prettier owns. Committing the raw output only moves the drift around. Set ts_formatter: TsFormatter::Command(vec!["prettier".into(), "--stdin-filepath".into()]) in iron-log's ClientsConfig, or add the two generated/ dirs to src-nuxt/.prettierignore. Then the checked-in files are stable no matter who regenerates them.
| }, | ||
| ], | ||
| { key: 'tags', label: 'Tags', type: 'relation-array', relationTo: 'tag', showInTable: true, showInDetail: true, showInForm: true }, | ||
| { key: 'created_at', label: 'Created At', type: 'string', required: true, showInDetail: true, showInForm: true }], |
There was a problem hiding this comment.
This is a real behaviour change, not formatting. Workout created_at changed from readOnly: true (no showInForm) to showInForm: true with no readOnly, here and in iron-log-md. So the PR description's claims ("no field, flag or value changes", "No data lost", "The real change there is formatting") are wrong for this file.
Failure: the admin UI now shows created_at as an editable form input on both create and edit. A user can rewrite a workout's creation timestamp from the edit form. This comes from the earlier is_read_only = ... (key == "created_at" && !is_required) generator change. Either it's intended, and should be called out and reviewed as such, or created_at should be read-only on update.
| [[package]] | ||
| name = "ontogen" | ||
| version = "0.3.1" | ||
| version = "0.7.1" |
There was a problem hiding this comment.
The drift will come back. examples-ci.yml already runs cargo build / cargo check on each example, and that runs build.rs and regenerates the committed trees in place. But CI never checks that the output matches what's committed. That's how iron-log ended up pinning ontogen 0.3.1 through several releases. Add a git diff --exit-code -- examples/ step after each build (and --locked on the cargo invocation). Then a stale generated tree or lockfile fails the PR, and nobody has to find it and hand-regenerate later.
| {pagination_js}\ | ||
| {list_has_query_js}\ | ||
| fields: [{fields_js}], | ||
| {pagination_js}{list_has_query_js} fields: [{fields_js}], |
There was a problem hiding this comment.
No regression test pins this fix. The PR notes that the registry tests assert on content, not layout. So putting a \ continuation back in this template (the exact bug fixed here) would still pass just full-check. A small assertion in src/clients/tests.rs on the emitted "\n {\n key: '" and "\n fields: [" substrings, or an insta snapshot of admin::generate output, would lock in the indentation.
| " {{ | ||
| key: '{module}', | ||
| plural: '{plural}', | ||
| label: '{label}', |
There was a problem hiding this comment.
label / pluralLabel (and key/plural) are interpolated without ts_escape, even though field labels a few lines below go through ts_escape. These values can come from NamingConfig.label_overrides / plural_label_overrides, which are user-supplied. Failure: label_overrides: {"author": "Author's Pick"} emits label: 'Author's Pick',, which is a TS syntax error in the generated registry. Wrap them in ts_escape(...) the same way generate_fields_for_entity does.
| { | ||
| key: 'workout_set', | ||
| plural: 'workout_sets', | ||
| label: 'Workout_set', |
There was a problem hiding this comment.
Module labels for multi-word modules come out as 'Workout_set' / 'Workout_sets'. NamingConfig::label (src/servers/types.rs:707) uses capitalize(module), which keeps the underscore. That text shows up in the admin UI. admin.rs already has field_label(), which gives "Workout Set". Reuse that, or a shared snake-to-title helper, as the default module label.
| name?: string | null; | ||
| muscle_group?: string | null; | ||
| equipment?: string | null; | ||
| notes?: string | null | null; |
There was a problem hiding this comment.
string | null | null: the regenerated Update DTO types show a doubled | null on every optional-nullable field (notes, name, duration_minutes, …). It type-checks, but it's a TS-bindings generator bug for Option<Option<T>> update fields, where the inner Option and the patch Option each add | null. This PR now commits it into the reviewed baseline. Worth deduping in the emitter so this baseline doesn't have to churn later.
| { key: 'name', label: 'Name', type: 'string', required: true, showInTable: true, showInDetail: true, showInForm: true }, | ||
| { key: 'muscle_group', label: 'Muscle Group', type: 'string', required: true, showInDetail: true, showInForm: true }, | ||
| { key: 'equipment', label: 'Equipment', type: 'string', required: true, showInDetail: true, showInForm: true }, | ||
| { key: 'notes', label: 'Notes', type: 'string', showInDetail: true, showInForm: true }], |
There was a problem hiding this comment.
The layout is still not what the template comment calls "intended". The closing ] of fields: hugs the last element (... }],), because generate_fields_for_entity (admin.rs:219) prepends \n to each item and never emits a newline before ]. Its trailing-comma check also uses the unfiltered entity.fields.len(), so it's wrong when the last field is FieldRole::Skip. If the goal is output that is stable for review, emit fields: [\n{items joined by ",\n"},\n ],, filtering first and then joining.
| Ok(notes) | ||
| } | ||
|
|
||
| pub async fn count_notes(&self) -> Result<u64, AppError> { |
There was a problem hiding this comment.
count_notes can disagree with list_notes. count_notes counts every path from list_paths, while list_notes goes through read_all, which continues past any path whose file stem isn't valid UTF-8. Failure: a vault containing a record with a non-UTF-8 filename reports count = N+1 while listing returns N rows, so pagination totals are off. Count list_ids(NOTES_DIR) instead, which applies the same stem filter.
Brings the examples' checked-in generator output back in line with what the pipeline actually emits, and fixes a generator bug found while doing it.
Two commits, separable.
1. The generator bug
Inside a Rust string literal, a trailing
\eats the newline and every leading space on the next line. The admin-registry template used\continuations to splice in two optional chunks, so it was silently dropping the indentation on the two lines that followed them:The optional chunks already carry their own trailing newline, so they splice inline and the continuations were never needed. Dropping them restores the intended layout, with a comment recording why
\must not come back.Output only — no field, flag or value changes. The registry tests assert on content rather than layout.
2. The regeneration
The examples commit their generated trees so diffs stay reviewable, but nothing regenerates them. They had drifted badly — iron-log's lockfile was still pinning ontogen 0.3.1.
What the rebuild pulls in, none of it hand-authored:
count_*store methods +PaginatorTraitimportsha2dependency chain in notes-kb / tasks-trackerAll four examples (
iron-log,iron-log-md,notes-kb,tasks-tracker) build against the regenerated output.Doing this now means the next generator change produces a diff that is only that change, rather than one carrying two releases of backlog.
A correction to what I reported on #178
On #178 I flagged that regenerating iron-log appeared to strip the
fields:metadata fromadmin-registry.ts, and guessed at aClientsConfig::schema_entitiesforwarding bug.That was wrong. The metadata is intact — 26 field keys and 4
fields:arrays, before and after. I had read the first 20 lines of a diff whose leading change was the indentation shift above, which re-diffed the whole file; the-lines I saw were re-added below my window.Pipelinedoes forwardschema.entitiescorrectly (src/pipeline.rs:583-587).The real change there is formatting: field objects went from multi-line blocks to one per line, 254 → 109 lines. No data lost.
Verification
just full-checkgreen — fmt, clippy, the full Rust workspace, and 43 vitest tests. Pluscargo checkon each of the four examples.