chore(content): declare the field that titles each model's entries - #191
Merged
Conversation
`@contentrain/types@1.0.0` makes `ModelDefinition.title_field` required.
Every consumer used to guess which field was an entry's title, and the
guess was wrong in ways that made listings unreadable — a hero slide
titled by a relation ID, an article titled by its slug.
This is the migration, so the bump has something valid to land on. It
has to come first: without it, a bumped Studio would fail validation on
its own dictionary.
Produced by `contentrain@0.9.2 validate --fix`, not by hand — the point
of the tool is that the choice and the rule behind it are the CLI's, and
a hand-written `title_field` would be exactly the guess this replaces.
4 dictionaries → key (the entry key is the title; the only legal value)
3 collections → name over slug / subject / description
1 singleton → headline
1 collection → name (starters)
Errors go 10 → 1. The one left is a false positive: the plan feature
whose id is `cdn-api-keys` has `key: "cdn.api_keys"`, and the secret
detector reads the name as a credential. Worth reporting upstream now
that `contentrain validate` exits non-zero — a CI step running it would
fail on a correctly-named feature flag.
Carried along, because the same command writes them:
- model files pick up canonical key order from `MODEL_FIELD_ORDER`,
which moved into `@contentrain/types`. `plans.json` had its top-level
keys scrambled; fields sort alphabetically now.
- two `error-messages` keys swap into canonical order.
- orphan meta records for `plans/community` and nine plan features.
They land as `source: import`, `status: draft` — the same shape every
neighbouring record already has, so nothing changes what the app
renders.
- `context.json` regenerates.
Run in an isolated copy rather than here: `--fix` works through the
`contentrain` branch, and this repo's is 44 commits behind `main` — the
CLI refused rather than writing onto stale content, which is the right
refusal and a separate thing to fix. Studio's own dictionary lives on
`main` and is edited by PR; the resulting files were brought over and
re-validated in place.
This was referenced Aug 13, 2026
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.
@contentrain/types@1.0.0makesModelDefinition.title_fieldrequired. This is the migration of Studio's own.contentrain/, so the bump (T07b) has something valid to land on — without it, a bumped Studio fails validation on its own dictionary.Produced by
contentrain@0.9.2 validate --fix, not by hand. The point of the tool is that the choice and the rule behind it are the CLI's; a hand-writtentitle_fieldwould be exactly the guess this feature replaces.What it chose
title_fieldkey— the only legal valuename— overslugandsubjectnameheadlineErrors go 10 → 1.
The one error left is a false positive
The plan feature whose id is
cdn-api-keyshaskey: "cdn.api_keys"— a feature name, not a credential. Worth reporting upstream now thatcontentrain validateexits non-zero: a CI step running it would fail forever on a correctly-named feature flag, and the only workaround is renaming the feature.Carried along, because the same command writes them
MODEL_FIELD_ORDERmoving into@contentrain/types.plans.jsonhad its top-level keys scrambled (descriptionfirst,id/kind/nameat the bottom); fields now sort alphabetically.error-messageskeys swap into order.plans/communityand nine plan features. They land assource: import,status: draft— the same shape every neighbouring record already has, so nothing changes what the app renders. I checked that before accepting it:statusis alreadydrafton every existing plan record, so nothing is being newly hidden.context.jsonregenerates.Why it was run in an isolated copy
--fixworks through thecontentrainbranch, and this repo'scontentrainis 44 commits behindmain. The CLI refused rather than writing onto stale content:That is the right refusal, and it points at something separate worth knowing: Studio's own dictionary is maintained on
mainby PR, so thecontentrainbranch here is vestigial — which also means Studio's chat agent editing Studio's own dictionary would write somewhere the app never reads. Out of scope here; flagging it.So the fix was produced in a throwaway copy of
.contentrain/on its owncontentrainbranch, and the resulting files were brought over and re-validated in place.Verified
contentrain@0.9.2 validate --root .— 10 errors → 1 (the false positive above)npx contentrain-query generate— 9 models, 12 files, cleanpnpm lint— 0 errors (7 pre-existing warnings)pnpm typecheck— cleanpnpm test— 141 files / 1196 testsNext
T07b: bump
@contentrain/types1.0.2 /@contentrain/mcp3.0.2 /@contentrain/query7.0.4, consumetitle_fieldin the entry-title resolution, and add the selector. That unblocks T05 → T08b → T06.Customer projects still need this same migration before they can be written to by a bumped Studio — Lanista/collabers included. That is a live-repo operation and is not part of this PR.