Skip to content

common-patterns.mdx tells authors master_detail defaults to set_null — it cascades, so the page reassures a reader out of the one check that would save their child rows #9164

Description

@os-zhuang

Filed unassigned by the domain:engine-core execution seat (#6367), PM session session_01NTKPDRoynY8i3HmdSFUxFj. Surfaced by the docs-drift probe on PR #9163 (#9002) and deliberately not fixed there — it predates that change and a docs rider on a code PR is the shape AGENTS.md pushes back on. Duplicate-searched by path and by keyword before filing.

The claim

content/docs/getting-started/common-patterns.mdx:95:

master_detail defaults to deleteBehavior: set_null; set deleteBehavior: cascade explicitly if you want child records deleted with the parent.

Both clauses are false

Measured against packages/objectql/src/engine.ts, which resolves the behaviour as:

fdef.type==='master_detail'
? (fdef.deleteBehavior==='restrict' ? 'restrict' : 'cascade')
: (fdef.deleteBehavior||'set_null')
  • A master_detail with nodeleteBehaviorcascades. It does not default to set_null; on that branch set_null is not even reachable — the ternary admits only restrict or cascade.
  • set_null is the default for the other branch (a non-master_detail reference with no deleteBehavior) — so the page has the two defaults swapped onto the wrong field type.
  • Therefore "set cascade explicitly if you want child records deleted" describes opting in to something you already have.

It also contradicts the repo's own reference pages, which are correct: content/docs/protocol/objectql/types.mdx:691 gives Deletion | Configurable | Always cascade, and the master_detail characteristics list says the same.

Why this is worth a card rather than a one-word fix

The harmful reading is the passive one. The clause that gets someone hurt is not the author who follows the instruction — opting in to a cascade you already have is a no-op. It is the author who reads "defaults to set_null", concludes their child rows are safe, and changes nothing. They then delete a parent and the children go with it, silently and by design.

That is the ADR-0049 declared-vs-enforced shape pointed at a human instead of at code: the page is not merely stale, it actively talks a reader out of the one check that would have protected their data. And it sits in getting-started/ — the pages read by people with the least context to notice the contradiction with types.mdx.

Same class as #8739 (an authoritative source assertion consulted as an input and found false) and #8586 — but this one is user-facing rather than internal, and the cost lands on a tenant's rows rather than on a reviewer's reasoning.

Not claimed

  • No engine defect. The engine's behaviour is correct and matches types.mdx; only common-patterns.mdx is wrong. Nothing here asks for a code change.
  • No sweep performed. One page, found by a probe scoped to a different question. Other getting-started/ pages were not audited for the same swapped-default shape — treat this as a sample.
  • Not measured against a live delete. The falsity is read off the engine's resolution expression and the two reference pages that agree with it, not from a driven cascade.

Suggested disposition (triage's, not mine)

Correct the sentence to match the engine, and consider whether it should say why — a master_detail child has no independent existence, which is what makes cascade the right default and is the fact the page was presumably trying to convey. Worth deciding at the same time whether getting-started/ should be stating per-type defaults at all, given it now demonstrably drifts from types.mdx.

Routing note: the fix lands entirely in content/docs/**, which the lane table anchors to domain:devx (#6023) — the deliverable's landing site, not the subject's domain. ⛔ This seat does not set domain:*; recording the suggestion for triage.

Backlinks: PR #9163 / #9002 (the probe that surfaced it) · content/docs/protocol/objectql/types.mdx:691 (the correct statement it contradicts).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions