Skip to content

docs(content): a tree field does not require reference — two pages said it did - #14890

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-13928-troubleshooting-tree-reference-line
Sep 3, 2026
Merged

docs(content): a tree field does not require reference — two pages said it did#14890
os-sam merged 1 commit into
mainfrom
claude/issue-13928-troubleshooting-tree-reference-line

Conversation

@claude

@claude claude Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes #13928

Two docs cells said a tree field requires a reference. Nothing enforces that, and the spec's own tests construct a reference-less tree and assert defined behaviour for it. Both cells now say what the other surfaces already said.

Before / after

content/docs/deployment/troubleshooting.mdx:78 — the card's line:

-**Symptom:** A `lookup`, `master_detail`, or `tree` field fails validation.
+**Symptom:** A `lookup` or `master_detail` field fails validation.

:80 ("Relational fields require a reference property pointing to the target object.") is untouched — it stays true for the two remaining types.

content/docs/data-modeling/validation-rules.mdx:542 — the second page, see "Second page" below:

-| `tree` | `reference` | Self-referencing; no automatic cycle check |
+| `tree` | — | Self-referencing; no automatic cycle check |

That table's second column header is Required Props (:517), so the old cell was the same claim in table form. The em dash matches the user row directly above it (:540) — likewise a reference-carrying type with no required prop — and is the same U+2014 byte the rest of the column uses.

Why — the triage census, quoted

Triage comment 5486903425 ran the card's census and tabulated four surfaces, three agreeing and one outlier. Quoted verbatim, untranslated:

现有四个面里,三个已经一致,文档是唯一的异类:

对「tree 需要 reference」的态度
field.zod.ts:1064-1065 (reference 字段自己的 docblock) 「required for these types」只点名 lookup / master_detail
field.zod.ts:1073 (describe) 「Target object name … for lookup/master_detail fields」
lint RELATIONSHIP_TYPES {lookup, master_detail}
troubleshooting.mdx:78 lookup, master_detail, or tree ← 唯一异类

⇒ 修复 = 把 :78tree 去掉。

All three agreeing surfaces re-read on origin/main 2263ca4d6 before editing:

  • packages/spec/src/data/field.zod.ts:1064-1065 — "Used by lookup and master_detail field types … The reference property is required for these types … the superRefine below enforces it".
  • packages/spec/src/data/field.zod.ts:1073.describe('Target object name (snake_case) for lookup/master_detail fields. …').
  • packages/lint/src/data-model-rules.ts:103const RELATIONSHIP_TYPES = new Set(['lookup', 'master_detail']);, consumed at :499 and :577 by relationship/missing-reference. tree is not in the set.

And the two readings that make "required" and "default self-reference" untenable rather than merely unenforced:

  • packages/spec/src/data/field-value.test.ts:69 and packages/spec/src/data/filter-dotted-head.test.ts:31 construct a tree with no reference and assert defined behaviour, so a gate demanding one would red the spec's own test surface.
  • examples/app-showcase/src/data/objects/field-zoo.object.ts:108f_tree: { type: 'tree', reference: 'showcase_category' } points at another object, so "defaults to self" is wrong for a shipped example.

Second page: validation-rules.mdx:542

The dispatch's H2 anticipated a second page in the same sentence family and allowed fixing it here only if it is the same one-line claim. It is: the Required Props cell for tree, stating the identical requirement in a table instead of a sentence. The PM's H2 grep missed it because the row carries no "require" wording of its own — the requirement lives in the column header.

Four conditions for taking it in place, measured rather than assumed:

  1. Same defect class — byte-for-byte the same claim, falsified by the same census.
  2. Mechanical, pinned by landed evidence — the correct cell is fixed by the sibling user row and by the three agreeing surfaces above. No judgement call was left open.
  3. No other claim holds the file — every one of the 60 open PRs was scanned by file list (REST GET /pulls/{n}/files, 60/60 readable, 0 hits on either path). Nearest neighbour is PR perf(datasource): size the primary SQL pool from OS_DATABASE_POOL_MAX #14776, which touches a different content/docs/deployment/ page. Neither page has churned on main since b1581b044.
  4. Same gate family, no new verification surfacenode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands re-derived at HEAD returns the same 29 commands for the two-path change set that the PM derived for the one-path change set. The second page added no family.

H2 control grep

The zero was verified with a control before it was believed. Control: master_detail across content/docs/** + skills/** returns 40 files, including skills/objectstack-data/SKILL.md — so the grep surface really covers both trees and a zero there means something.

Sweeping every table row keyed on `tree` across both trees returns six rows. Only validation-rules.mdx:542 asserts the requirement. The two skills/** rows are left alone and nothing governed is touched:

row column it sits under verdict
content/docs/data-modeling/validation-rules.mdx:542 Required Props the same claim — fixed here
skills/objectstack-data/rules/field-types.md:91 Key Config true as written — reference is the relevant knob, not a requirement
skills/objectstack-data/rules/relationships.md:11 Required already reads Optional — agrees with the status quo
content/docs/data-modeling/field-type-decision-tree.mdx:176 When to Use no requirement claim
content/docs/ui/views.mdx:92 view kinds, not field types unrelated
skills/objectstack-ui/SKILL.md:48 view kinds, not field types unrelated

A "require / must have / mandatory / missing" sweep near `tree` across both trees returns nothing relevant either.

Gates

Re-derived on the actual changed paths at the final commit — node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, which takes its own change set from the merge base (2263ca4d6, three-dot) and confirmed --repo against this checkout's origin. 29 commands, all run at 5df44f134, exit code captured before any pipe:

  • 28 green. Among their own verdict lines: check-doc-frontmatter — "2 content root(s) verified … content/docs 404, content/blog 3"; check-docs-single-h1 — "404 page(s) under content/docs/ carry no body-level # heading"; check-doc-anchors — "295 internal #fragment link(s) across 409 source file(s) all resolve to a real heading"; check:docs — "229 generated files in sync with packages/spec"; check:doc-security-posture — "27 ObjectSchema.create example(s) in 226 marked block(s) across 236 prose file(s) in 2 root(s) carry an os validate-clean security posture"; check:skill-examples — "256 prose examples type-check across 3 surface(s)"; check:doc-authoring — "393 files clean".
  • 1 NOT MEASURED, not a red: node scripts/check-test-completeness.mjs exits 3 with "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named", and its own text prescribes the reading: "running the family locally, record this gate as NOT MEASURED. ⛔ It is not a red, and there is nothing here to fix." CI tees the log and passes the path, so CI is unaffected.

Four gates first came back prerequisite-blocked on unbuilt packages (check:doc-formula-expressions, check:doc-security-posture, check:docs, check:skill-examples) rather than being reported as NOT MEASURED: @objectstack/lint, @objectstack/formula, @objectstack/spec and @objectstack/client-react were built under the shared verify lock (scripts/pm/os-verify-lock.sh, VERDICT command-exit 0 on both runs) and all four then measured green.

Changeset

None, deliberately — skip-changeset is on this PR. The rule is "publishes nothing from any released package", and this diff is two content/docs/** cells:

  • apps/docs, the only workspace that consumes content/docs, is private: true.
  • No released package ships content/docs: the sole package.json in packages/ that mentions the path is plugin-webhooks, and the mention is prose inside its description; its files is ["dist","README.md","CHANGELOG.md"].
  • Repo precedent agrees — the seven most recent content/docs-only commits on main (89a156af8, db7f3e492, 365a740a8, a69dfde80, 4485f7dad, 63fb473a9, 167bcb2e1) each carry zero .changeset/ files.

The Check Changeset job's own exemption text names the label as "the author's explicit opt-out", meaning "this PR declares no release of its own" — which is what this is.

Deliberately not in this PR

  • packages/lint (RELATIONSHIP_TYPES) — unchanged; it is one of the three surfaces this PR converges the docs onto.
  • packages/spec/src/data/field.zod.ts — unchanged; two other cards are writing that file this round.
  • ⛔ Triage's fenced residual — whether a reference-less tree being judged relation and materialising deleteBehavior makes sense — is not answered here. This docs fix holds whichever way that lands. Method precedent for the census: [spec] FieldSchema accepts a lookup/master_detail with no reference target, though its own TSDoc calls the key required #13632 / PR fix(spec): require a non-empty reference on lookup/master_detail fields #13927.
  • The Self-referencing descriptor in the same validation-rules.mdx row is a different claim from the requirement one and is left as-is; it is reported to the PM as an out-of-scope finding, since field-zoo.object.ts:108 makes "self-referencing" over-narrow rather than false, and the wording is spread over five surfaces including two governed skills/** files.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…s said it did

`reference` is required for `lookup` and `master_detail` only. Three surfaces
already agree on that and two docs pages disagreed with all three:

- `packages/spec/src/data/field.zod.ts:1064-1065` (the `reference` docblock)
  names `lookup` and `master_detail` as the types the superRefine enforces it for.
- `packages/spec/src/data/field.zod.ts:1073` (`.describe()`) says "Target object
  name (snake_case) for lookup/master_detail fields".
- `packages/lint/src/data-model-rules.ts:103` —
  `RELATIONSHIP_TYPES = new Set(['lookup', 'master_detail'])`, consumed at :499
  and :577 by `relationship/missing-reference`. `tree` is not in the set.

A reference-less `tree` is a shape the spec's own tests construct and assert
defined behaviour for — `field-value.test.ts:69` (`referenceTargetOf` returns
undefined) and `filter-dotted-head.test.ts:31` (still classified `relation`) —
so no gate rejects one and none should: the docs were asserting a requirement
nothing enforces. A default-self-reference reading is falsified too, by
`examples/app-showcase/src/data/objects/field-zoo.object.ts:108`, where a `tree`
field points at `showcase_category` rather than at its own object.

Two cells, both stating the same claim:

- `content/docs/deployment/troubleshooting.mdx:78` drops `tree` from the symptom
  line. The Cause line at :80 stays true for the two remaining types.
- `content/docs/data-modeling/validation-rules.mdx:542` — the "Quick Validation
  Summary" table's second column is `Required Props` (:517), and the `tree` row
  listed `reference` there. It becomes an em dash, matching the `user` row beside
  it, which is likewise a reference-carrying type with no required prop.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE

os-sam commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Landing provenance (seat, 08:16Z) — ready + auto-merge (squash) from here.


Generated by Claude Code

@os-sam
os-sam marked this pull request as ready for review September 3, 2026 08:15
@os-sam
os-sam enabled auto-merge September 3, 2026 08:15
@os-sam
os-sam added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit 3ad5680 Sep 3, 2026
37 checks passed
@os-sam
os-sam deleted the claude/issue-13928-troubleshooting-tree-reference-line branch September 3, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants