Uh oh!
There was an error while loading. Please reload this page.
fix(spec): require a non-empty reference on lookup/master_detail fields - #13927
Conversation
…r_detail superRefine on the relationship types (ADR-0049 declared = enforced): a lookup / master_detail whose reference is missing or '' is refused at parse with a prescriptive message on the reference path. TSDoc aligned; pins for missing/empty/legal on both types; the three key-absence sample fixtures that used a bare lookup move to legal shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2
…sus line The changeset gains the not-required (no-migration-prescription) marker mirroring the #11519/#11842/#13733 narrowing precedents; the superRefine insertion shifted field.zod.ts line numbers, so the system-context page anchor is re-anchored by the census --fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2
📓 Docs Drift CheckThis PR changes 1 package(s): 27 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 128 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 e80b881f55da1c500d8d261d222ec98dc6c9156c && git checkout e80b881f55da1c500d8d261d222ec98dc6c9156c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 55519d50363147da03df0af068fb82fcc6d1d8c1 e7407339c968d096bf4e6f945117036dae250fbb && git checkout -B drift-repro 55519d50363147da03df0af068fb82fcc6d1d8c1 && git merge --no-ff e7407339c968d096bf4e6f945117036dae250fbb
node scripts/docs-audit/affected-docs.mjs --json 55519d50363147da03df0af068fb82fcc6d1d8c1
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#13632
Contract review: this PR carries
needs:contract-review(Clause-② — it changes contract accept/reject behaviour in packages/spec), stated here as the second carrier alongside the label.What
FieldSchemanow refusestype: 'lookup'/type: 'master_detail'whosereferenceis missing or the empty string, via a new check in the existing superRefine chain ofpackages/spec/src/data/field.zod.ts— the ruling on the card (ADR-0049 enforce-or-remove, option 1). The refusal is prescriptive on thereferencepath: it names the type, the key, the expected shape (a snake_case target object name) and the fix, and carries no issue number (doc-authoring discipline). The key's TSDoc — which has always calledreferencerequired on these two types — now also states the enforcement. No key is removed, renamed or re-shaped: this is an accept-set narrowing only. Empty string and absence are refused alike (the card measured both as accepted before).Premise measurement (ruling ②, taken BEFORE the tightening)
Census over the whole tree at 8c6a7fc, three channels:
type: 'lookup'/type: 'master_detail'occurrence): 515 with a non-emptyreference(positive), 179 without — every one triaged below; 0 are authored objects that FieldSchema parses.Field.lookup(...)/Field.masterDetail(...)(both take the target as a required first positional argument): 209 with a non-empty string-literal target; 22 flagged for review, all resolved as comments, docstrings, markdown API tables, or old-signature blog snippets — 0 real targetless calls.Positive controls proving the pipeline reads real hits: the showcase field-zoo's
f_lookup(targetshowcase_account) andf_master_detail(targetshowcase_project) surface through the same scan; the card's ownreference_tocontrol still refuses withunrecognized_keysafter the change.Verdict: zero existing authored objects depend on a targetless lookup/master_detail. The premise holds; the narrowing was executed (no fork). Corroborating: lint's
relationship/missing-reference(error severity, non-empty check over exactly lookup + master_detail) has long graded the same hole an error, and the troubleshooting docs page already documents missingreferenceas a validation failure — the publish seam was the one door left open.The 179 literal negatives, triaged (three-way, per the wizard-tightening precedent)
LOOKUP_TARGET_MISSINGguard), driver fixtures fed straight to the driver (below), lint fixtures fed to pure stack-to-findings validators, and docs that deliberately show the wrong shape as wrong (the field-types skill guide and the troubleshooting page).FieldSchema.parse— the maxLength/minLength absence pins infield.test.tsand the materialization pin infield-autonumber-default-format.test.ts. Their subject is key-absence propagation, not the lookup accept surface; the lookup sample now carriesreference: 'company', other types unchanged.reference_to/referenceTo/targetalias fixtures across drivers, lint and spec already refuse viaunrecognized_keysand still do.Blast radius noted, deliberately untouched
driver-mongodb (#13222):
syncCollectionSchemadeclining to build the lookup index for a targetless def stays in place as runtime defense for stored/legacy artifacts, and its tests still pass — but the comment inside its "does not index a lookup that declares no target" case, which records that both targetless shapes "parse successfully" on FieldSchema, is now stale as a statement about the current schema. Recorded here for triage rather than edited: driver code and driver tests are out of this card's scope per the dispatch.Verification
referencepath; the two legal shapes and thereference_topositive control are unchanged.git diff HEADplusgit hash-objectequal to the HEAD blob (d4e3c6b6). The spec suite importsfield.zod.tsby relative source path, so no dist rebuild sits in this ablation's resolution path.git rev-parse --short HEADfrom the same tree the run measured): full@objectstack/specsuite — verdict line "Test Files 445 passed (445) / Tests 11938 passed (11938)" — chained withpnpm --filter @objectstack/spec typecheck(tsc + scripts + tests programs), lock entry-point verdict "VERDICT command-exit 0" covering both.check:authorable-surface,check:strictness-ledger,check:docs,check:doc-authoring,check:dispatcher-error-vocabulary,check:engine-double-contract,check:where-matcherand the changeset family, after three repairs — the adr-0087 marker below, a system-context census re-anchor (--fix; the superRefine insertion shiftedfield.zod.tsline numbers by two), and building@objectstack/formula+@objectstack/lintsocheck:doc-formula-expressionscould measure (then green).check-dev-prereqs,check:dual-build-cjs-loads,check:type-check-coverage,check:type-check-debt(all need the full workspace closure built),check-test-completeness(needs a saved turbo test log),check:pm-half-states(route refused from this container; its exit 3 self-describes as an unread instrument). Repo-widepnpm lintis CI's run.Changeset / ADR-0087
@objectstack/specminor with the BREAKING narrative, per the #11519 / #11842 / #13733 narrowing precedents. ADR-0087 disposition:not-required (no-migration-prescription)— no tombstone exists, the parse refusal is the channel that reaches an affected author, and which target a targetless relationship was meant to point at is authoring intent no migration entry can decide; marker in the changeset body.Generated by Claude Code
Generated by Claude Code