feat(cli,types): serve UI reads the declared title, and the secret detector stops flagging docs - #115
Merged
Merged
Conversation
…tector stops flagging docs
Two things this project needed once title_field shipped.
**serve-ui was still guessing.** Its column list called
`Object.keys(desc.fields)` under a comment claiming that preserved definition
order. It does not — model JSON is written with canonically sorted keys, so it
was alphabetical, which is the exact problem `order` exists to fix. Columns now
use `orderedFieldNames`, headers use `resolveFieldLabel` (raw key kept in the
`title` attribute so nothing becomes undiscoverable), and the default visible
columns lead with `title_field`. Both helpers come from @contentrain/types so
every consumer resolves them identically. serve-ui gains a workspace dependency
on types; it is private and bundled, and types is pure with no Node imports.
**The secret detector was flagging documentation about secrets.** Bare-prefix
matching meant `task_id` and `risk_level` tripped `sk_`, every page documenting
`Authorization: Bearer <token>` tripped `Bearer `, and a local
`postgres://localhost:5432/mydb` tripped the connection-string rule. Seven of
this repository's twelve validation errors were that — same shape as the
doctor --usage finding: a check firing correctly and burying what matters.
Patterns now match a credential-shaped value: prefixes need their key body, a
bearer token needs a token rather than `<token>`/`$TOKEN`/`{{token}}`, an api
key needs to be assigned one, a connection string needs embedded credentials.
18 cases pinned in tests, from this repo's own docs.
Two pre-existing assertions changed rather than worked around, because they
asserted the false positive: `my_api_key_value` and `mongodb://localhost/test`
are no longer secrets. Both are called out in the test with the reason.
Result on this repo: 12 errors -> 5, and the 5 are real. Running
`validate --fix` then created the four missing tr.json files, which exposed 10
genuine untranslated entries underneath — MCP correctly refuses to invent a
translation. The content branch also advanced and now carries all 11 migrated
models; the working tree was untouched throughout, as the transaction design
intends.
✅ Deploy Preview for contentrain-ai ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Two things this repository needed once
title_fieldshipped, plus what fixingthem exposed in its own content.
serve-ui was still guessing
Its column list called
Object.keys(desc.fields)under a comment claimingthat preserved definition order. It does not — model JSON is written with
canonically sorted keys, so it was alphabetical. That is the exact problem
orderexists to fix: on a sixteen-field article model,authorfirst andtitlefifteenth, each column headed by its raw key (body_public,is_category_hero).orderedFieldNames— a declaredorderwins, fieldswithout one keep today's alphabetical fallback
resolveFieldLabel; the raw key stays as thetitleattribute so the underlying field is still discoverable
title_fieldwhen the model declares one.The existing required-plus-simple-type heuristic fills the remaining slots
and still covers models that predate the property
Both helpers come from
@contentrain/types, so serve-ui and any other consumerresolve them identically instead of each reimplementing the fallback chain.
serve-ui takes a workspace dependency on types — it is private and bundled, and
types is pure with no Node imports, so it bundles for the browser cleanly.
The secret detector was flagging documentation about secrets
SECRET_PATTERNSmatched bare prefixes:task_idsk_risk_levelsk_Authorization: Bearer <token>Bearerpostgres://localhost:5432/mydbpostgres://The api_key parameter is requiredapi_keySeven of this repository's twelve validation errors were this — it stores
its own documentation as content, so every page explaining Bearer auth was a
finding. Same shape as the
doctor --usagefix: a check firing correctly andburying what matters.
Each pattern now matches a credential-shaped value rather than prose about
credentials — prefixes need their key body, a bearer token needs an actual
token rather than
<token>/$TOKEN/{{token}}/YOUR_TOKEN, an api keyneeds to be assigned one, a connection string needs embedded credentials.
18 cases are pinned in tests, taken from this repo's own docs.
Two pre-existing assertions changed rather than being worked around, because
they asserted the false positive:
my_api_key_valueandmongodb://localhost/testare no longer reported. Both carry a comment sayingwhy. A check that fires on the wrong thing is not a strict check; it is one
people learn to scroll past.
What that exposed
Validation on this repo went 12 errors → 5, and the five are real. Running
validate --fixcreated the four missingtr.jsonfiles, which then surfaced10 genuinely untranslated entries underneath. MCP correctly refuses to invent a
translation, so those stay reported.
The empty
tr.jsonfiles are the right state: the locale is declared inconfig, so the file should exist, and "these entries are untranslated" is more
actionable than "the file is missing".
The branch also carries
[contentrain] validate: auto-fix— the transactionadvances the checked-out branch via
update-refalongside the content branch,which is the documented design. The working tree was never touched.
Incidentally: the
contentrainbranch had all 11 models withouttitle_fieldand is now fully migrated, because every transaction merges base into its
worktree first. Worth knowing for the project migrations — a stale content
branch heals on the first write, it does not need separate handling.
pnpm lint,typecheck,vue-tsc,build, 1650+ tests,plugin:build,release:check— all green.🤖 Generated with Claude Code