Skip to content

fix(examples): require the master on showcase field-zoo's f_master_detail - #14449

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-13723-field-zoo-master-detail-required
Sep 2, 2026
Merged

fix(examples): require the master on showcase field-zoo's f_master_detail#14449
os-zhuang merged 3 commits into
mainfrom
claude/issue-13723-field-zoo-master-detail-required

Conversation

@claude

@claude claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #13723

One line: showcase_field_zoo.f_master_detail now declares required: true, matching how every other master_detail in the authored corpora spells it.

Premise re-check on origin/main

Verified at merge base 6aea1f559. examples/app-showcase/src/data/objects/field-zoo.object.ts:107 read exactly as the card described, with no required: true:

f_master_detail: Field.masterDetail('showcase_project', { label: 'Master-Detail → Project' }),

Premise holds.

Census re-measurement

The card's claim — that this is the only master_detail in any authored corpus without required: true — was re-measured rather than taken on trust. Every Field.masterDetail() declaration in the loadable authored corpora, flagged when its options object carries no required: true:

grep -rlZ --include='*.ts' 'Field\.masterDetail(' \
  examples/app-showcase examples/app-crm examples/app-todo \
  packages/apps packages/create-objectstack/src/templates packages/platform-objects \
| xargs -0 perl -0777 -ne '
  while (/Field\.masterDetail\((.*?)\}\)/gs) {
    my ($body, $pre) = ($1, substr($_, 0, pos($_)));
    my $line = 1 + ($pre =~ tr/\n//) - ($body =~ tr/\n//);
    printf "%-70s %s\n", "$ARGV:$line", ($body =~ /required:\s*true/ ? "required:true" : "MISSING required:true");
  }'

Output on the pre-fix tree — 7 declarations, exactly 1 missing:

examples/app-showcase/src/data/objects/invoice.object.ts:181           required:true
examples/app-showcase/src/data/objects/task.object.ts:37               required:true
examples/app-showcase/src/data/objects/expense-report.object.ts:131    required:true
examples/app-showcase/src/data/objects/team.object.ts:41               required:true
examples/app-showcase/src/data/objects/team.object.ts:42               required:true
examples/app-showcase/src/data/objects/field-zoo.object.ts:107         MISSING required:true
examples/app-crm/src/objects/opportunity-line-item.object.ts:28        required:true

A second sweep for the non-builder spelling (a bare type: 'master_detail' field literal) across the same corpora returns nothing, so the builder scan above is the complete population. The census card #13699 is confirmed: this was the last one.

Seed rows already comply

Both seeded zoo specimens supply the value, so this changes no data and turns nothing red — examples/app-showcase/src/data/seed/index.ts, the two records of the fieldZoo seed:

  • line 338, Specimen — Full: f_master_detail: 'Website Relaunch'
  • line 351, Specimen — Minimal: f_master_detail: 'Data Platform'

Those are the only two records in that seed, so the object has no row that would newly fail the required check.

What actually moves

Ablation, on committed state: the fix restored from HEAD~1 into the worktree (mutation confirmed on disk by blob hash plus occurrence counts of both the injected and the removed text), the instrument re-run, then restored with git checkout HEAD -- and re-proved clean (git diff HEAD empty, working-tree hash equal to the HEAD blob).

tree objectstack lint totals relationship/master-detail-required
pre-fix 413 warning(s), 26 suggestion(s) 1 — master_detail "showcase_field_zoo.f_master_detail" → showcase_project should be required at objects[9].fields.f_master_detail.required
this PR 412 warning(s), 26 suggestion(s) 0

Delta is exactly minus one, exactly that rule, exactly that field. Nothing else in the report moves.

One correction to the record, since it lands in the branch's commit message and is wrong there: that message names objectstack validate as the command that was warning. It is not — the rule lives in packages/lint/src/data-model-rules.ts and reaches the CLI through objectstack lint. Measured both ways: objectstack validate prints 33 warnings on the pre-fix and post-fix trees alike, byte-identical, so it never read this rule at all. The table above is the accurate reading.

Consumer fix — the card's "turns nothing red" clause was wrong

CI caught a consumer the census did not look for. On head e9c424e7, Dogfood Regression Gate (2/3) failed (run 33603420183, job 100162026771):

packages/qa/dogfood/test/temporal-storage-e2e.dogfood.test.ts:90
  write f_time hm: expected 400 to be 201
Insert operation failed {"object":"showcase_field_zoo","error":{"message":"Master-Detail → Project is required"}}

Why the premise missed it: the card reasoned about the seed, and the seed really does comply — both zoo specimens set f_master_detail. What neither the card nor my census re-measurement asked was who else writes zoo rows. temporal-storage-e2e.dogfood.test.ts creates its own fixtures through the real REST write path and supplied only name plus a temporal field, relying on a comment in that file which asserted the object "requires only name". Making the field required is exactly what refuses those inserts. A census over declarations cannot see a consumer that writes records; that is the gap, and it is worth naming rather than papering over.

The fix is local to the call sites and does not weaken the field. The suite now seeds its own master chain in beforeAllshowcase_account, then showcase_project (which itself declares a required lookup to the account, so the order is forced) — and passes that id to each of the four zoo inserts, including the epoch-rejection case, so the 400 that test asserts is still about f_time and not about a missing master. Created rather than read out of the seed, deliberately: this file's assertions depend on it owning every row it reads.

Files touched:

  • packages/qa/dogfood/test/temporal-storage-e2e.dogfood.test.ts — master chain seeded in beforeAll; f_master_detail added to the four inserts; the stale "requires only name" comment corrected.

No other writer needed changing. field-zoo-roundtrip.dogfood.test.ts already resolves f_master_detail through REFERENCE_TARGETS, which is why it stayed green; action-params-contract.dogfood.test.ts only invokes actions. A sweep of every remaining showcase_field_zoo reference in the tree finds name-list assertions, comments, and one read-only page visit.

No test was skipped, quarantined, or relaxed, and showcase_field_zoo.f_master_detail remains required: true.

Verification

Re-run in full after the consumer fix, at head b0e788ee3 (which includes a merge of origin/main). Every heavy command through scripts/pm/os-verify-lock.sh, exit codes captured before any pipe, verdicts read from the lock's own VERDICT line.

Reproduce-then-prove on the dogfood failure, run from committed state with a restore trap:

tree run result
pre-fix (the tree CI reddened) vitest run test/temporal-storage-e2e.dogfood.test.ts exit 1 — AssertionError: write f_time hm: expected 400 to be 201, engine log Insert operation failed {"object":"showcase_field_zoo","error":{"message":"Master-Detail → Project is required"}}; 1 file failed, 8 tests skipped
this PR same command exit 0 — 1 file passed, 8 tests passed

The mutation was confirmed on disk before the pre-fix run (blob b0790b8ea against the HEAD blob 922bc1339, with occurrence counts of both the added and the removed text checked), and the restore afterwards was proved rather than assumed (git checkout HEAD --, then git diff HEAD empty, git status --porcelain empty, working-tree hash equal to the HEAD blob).

Then, on the fixed tree:

  • whole dogfood suite, unshardedpnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2: exit 0, 129 files passed | 1 skipped (130), 1003 tests passed | 3 skipped (1006). This is the check that no other consumer was missed; nothing outside the one file needed touching.
  • pnpm --filter @objectstack/dogfood typecheck — exit 0
  • pnpm --filter @objectstack/example-showcase typecheck — exit 0
  • showcase suite, vitest run --maxWorkers=2 — exit 0, 26 files, 364 tests
  • pnpm --filter @objectstack/example-showcase validate — exit 0
  • pnpm lint (eslint . --no-inline-config, whole repo, not narrowed) — exit 0

Derived union re-run on the final head — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths, deriving its own change set: it now sees 2 paths and emits 32 commands, up from 17 before the dogfood file joined. 30 exit 0, plus pnpm check:nul-bytes exit 0.

Two are NOT MEASURED locally rather than green, by their own exit code 3 and their own printed verdict — unchanged from the first round:

  • check-test-completeness — grades a saved turbo run test log the derived family cannot hand it; it prints "the local reading for this gate is NOT MEASURED ... it is not a red".
  • check:dual-build-cjs-loads — reads built output, and eight packages outside this card's dependency closure have no dist/: "PREREQUISITE NOT MET ... this is NOT a pass: nothing was measured."

Changeset

None, deliberately. examples/app-showcase is "private": true and publishes nothing, so this PR declares no release of its own and carries skip-changeset — the same route taken by the most recent examples-only change to land (#14090 — an examples-only diff carrying skip-changeset and no changeset).

🤖 Generated with Claude Code

https://claude.ai/code/session_01GDA48PuRFrHyRfdkBz8m21

Generated by Claude Code


Generated by Claude Code

…tail

`showcase_field_zoo.f_master_detail` was the only `master_detail` declaration
across the loadable authored corpora that did not set `required: true` — a
detail record cannot exist without its master, and `objectstack validate` was
warning about exactly this one field (`relationship/master-detail-required`).

Both seeded zoo specimens already supply the value, so no data changes and
nothing turns red; this is example hygiene, and it zeroes the migration list a
future promotion of that rule from `warning` to `error` would produce.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GDA48PuRFrHyRfdkBz8m21
`showcase_field_zoo.f_master_detail` is now required, and this suite creates
its zoo rows through the real REST write path supplying only `name` plus a
temporal field. Every insert answered 400 "Master-Detail → Project is
required", failing at `write f_time hm: expected 400 to be 201`.

The suite now seeds its own master chain in `beforeAll` — `showcase_account`,
then `showcase_project`, which declares a required lookup to the account, so
the order is forced — and passes that id to each of the four zoo inserts. The
epoch-rejection case gets it too, so the 400 it asserts is still about `f_time`
rather than about a missing master. Created rather than read out of the
showcase seed on purpose: this file's assertions rely on it owning every row it
reads.

Also corrects the comment that claimed the object "requires only `name`".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GDA48PuRFrHyRfdkBz8m21
@github-actions github-actions Bot added size/s and removed size/xs labels Sep 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json a98b61b3ef695431db26097a28ae8e5f1dec8fdfpackageMentionDocs.

@github-actions github-actions Bot added the tests label Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 08:25
@os-zhuang
os-zhuang enabled auto-merge September 2, 2026 08:25
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 2, 2026
Merged via the queue into main with commit ecbb6fd Sep 2, 2026
39 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-13723-field-zoo-master-detail-required branch September 2, 2026 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants