Uh oh!
There was an error while loading. Please reload this page.
fix(spec): name reference, not the rejected referenceTo alias, in the public-picker prose - #13198
Conversation
… the public-picker prose `FormFieldPublicPickerSchema.object` told authors the picker target resolves from `referenceTo` on the parent object's field definition. `referenceTo` is not a key `FieldSchema` accepts — it is a rejected alias listed only so `strictUnknownKeyError` can offer a rename hint, so an author who followed the sentence had their whole object metadata refused at parse. The `.describe()` half is the sharper one: it is published into the generated JSON Schema and the reference docs, so it reached authors (and AI authors reading the generated schema as ground truth) who never open this file. Purely textual. Nothing about the runtime resolution changes, and this takes no position on the REST route's legacy-spelling chain — the sentence is wrong under either outcome, because a conformant authored field carries `reference` in both worlds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
… prose, add changeset `check:generated` proved exactly one artifact stale after the describe change: `content/docs/references/ui/view.mdx`. Regenerated with the repo's own `pnpm --filter @objectstack/spec gen:docs`, never by hand. The false sentence rendered TWICE on that page — the picker schema is emitted both nested under `FormField` and standalone as `FormFieldPublicPicker` — which is the published half of the defect the card names. Changeset is a `@objectstack/spec` patch, matching in-repo precedent for describe-string corrections that regenerate a references page. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ade189fc7a09fefc37fe086e30ad5bbe0360396b && git checkout ade189fc7a09fefc37fe086e30ad5bbe0360396b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin c25bfb33271b49b2c77e8a25da0ad7f96b9eed49 cac1718642fcf705f0b180206552253943ea1259 && git checkout -B drift-repro c25bfb33271b49b2c77e8a25da0ad7f96b9eed49 && git merge --no-ff cac1718642fcf705f0b180206552253943ea1259
node scripts/docs-audit/affected-docs.mjs --json c25bfb33271b49b2c77e8a25da0ad7f96b9eed49 |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#13138
FormFieldPublicPickerSchema.objectstated twice — once in the docblock, once in the published.describe()— that the picker target resolves fromreferenceToon the parent object's field definition.referenceTois not a keyFieldSchemaaccepts. It is a rejected alias, listed in the field schema's alias map (packages/spec/src/data/field.zod.ts) only sostrictUnknownKeyErrorcan offer a rename hint when a parse fails on it. An author who followed the sentence got their whole object metadata refused at parse — a failure, not a degraded render.Premise re-verified on this branch
Re-verified before editing, against the built
packages/spec/dist/data/index.mjs, with the card's own three-level control. A two-level control cannot separate "rejected" from "not measured"; the negative control is what proves the harness can see a refusal at all. Verbatim readings:The premise reproduces exactly:
referenceaccepted, an invented key refused without a rename hint,referenceTorefused with one.The published half really did ship
The
.describe()is the sharper site because it is published.gen:docsproved it: the false sentence rendered twice oncontent/docs/references/ui/view.mdx— the picker schema is emitted both nested underFormFieldand standalone asFormFieldPublicPicker. Both are corrected.Generated artifacts
check:generatedproved exactly one artifact stale, verdict quoted before and after.Before, on the edited source:
Regenerated with the repo's own tooling —
pnpm --filter @objectstack/spec gen:docs, never by hand. After, on the final head:Sibling sweep (this card's lane only)
Swept
packages/specfor other prose namingreferenceToas an accepted key. This was the only instance. The other mentions are all correct and were left alone — they describe it as a rejected alias, which is what it is:data/field.zod.ts— the alias-map entry itself (referenceTo: 'reference'), the declaration that makes the rename hint possibleui/action.zod.ts—ACTION_PARAM_KEY_ALIASES, folding the spelling ontoreferenceshared/alias-probe.ts,shared/suggestions.test.ts,ui/action.test.ts— probe/suggestion machinery and its pinsA wider check for other rejected
FieldSchemaaliases named in spec prose (relatedTo,targetObject,lookupObject,isRequired,mandatory,notNull, and others) found only correct usages, each explicitly labelled an "alias spelling".packages/restis #13137's lane and is untouched.Scope
Prose only. No schema shape, no accept/reject movement, no key added or removed — every previously-valid input parses byte-identically. Runtime resolution is untouched.
This takes no position on #12920 (whether the REST route's legacy-spelling fallback chain survives). The sentence was wrong under either outcome, because a conformant authored field carries
referencein both worlds — and the route already readsdef?.referencefirst, before any fallback. That independence is why this card lands alone.Verification
Gate family derived mechanically with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no hand-fed paths; three-dot semantics against the merge base). Union re-run after the final commit, atcac171864, exit codes captured before any pipe.49 of 53 derived gates PASS, including every load-bearing one for this card:
Plus the convention-triggered gate and the affected package, same head:
pnpm --filter @objectstack/spec test— 443 test files, 11752 tests, all passed. That run was at70b067251;git diff 70b067251 cac171864 -- packages/is empty, so the test inputs are byte-identical at the final head.4 gates are NOT MEASURED locally, none of them a red — each refuses by its own verdict text rather than returning a false green, and each is a container/invocation limit, not a finding:
check:dual-build-cjs-loadsPREREQUISITE NOT MET — this gate reads built output(needs a full repopnpm build)check-dev-prereqs.mjsdist/; needs a full repopnpm buildcheck-test-completeness.mjscheck-half-states.mjsPREREQUISITE NOT MET — the token in the environment is not a valid GitHub credentialThree further gates initially reported
PREREQUISITE NOT METand were converted into real measurements by building what they read (@objectstack/formula,@objectstack/lint,@objectstack/client-react,@objectstack/client), after whichcheck:doc-formula-expressions,check:doc-security-postureandcheck:skill-examplesall pass.Declared narrowing:
gen:docswas run outside the shared heavy-verify lock after ~18 minutes at the head of its queue with no progress. The heavy half (the spec build) was already complete anddistverified current for the edit, so the remaining step was a docs render, not a build. CI runs the full farm regardless.Changeset
@objectstack/spec: patch. A published.describe()string does ship, and in-repo precedent for exactly this shape — a describe correction that regenerates acontent/docs/references/**page — carries one:mongo-options-describe-boundaryandvisiblewhen-describe-bound-rootsare both@objectstack/spec: patch. Theskip-changesetclosed list (docs/adr/**,.claude/**,scripts/pm/**, tests/workflow, comments) does not cover this diff.Landing posture
needs:contract-reviewis attached (clause-② PATH leg: the diff touchespackages/spec/src/**). The CONTENT leg does not apply — nothing about what parses changes.This PR stays DRAFT. It is not to be marked ready, auto-merged or enqueued: the PM seat's tier fuse is down and contract review is parked for the review chain. A PR waiting in draft is the correct end state here, not a failure.
Generated by Claude Code