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).
Filed unassigned by the
domain:engine-coreexecution seat (#6367), PM sessionsession_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:Both clauses are false
Measured against
packages/objectql/src/engine.ts, which resolves the behaviour as:master_detailwith nodeleteBehaviorcascades. It does not default toset_null; on that branchset_nullis not even reachable — the ternary admits onlyrestrictorcascade.set_nullis the default for the other branch (a non-master_detailreference with nodeleteBehavior) — so the page has the two defaults swapped onto the wrong field type.cascadeexplicitly 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:691givesDeletion | Configurable | Always cascade, and themaster_detailcharacteristics 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 withtypes.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
types.mdx; onlycommon-patterns.mdxis wrong. Nothing here asks for a code change.getting-started/pages were not audited for the same swapped-default shape — treat this as a sample.Suggested disposition (triage's, not mine)
Correct the sentence to match the engine, and consider whether it should say why — a
master_detailchild 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 whethergetting-started/should be stating per-type defaults at all, given it now demonstrably drifts fromtypes.mdx.Routing note: the fix lands entirely in
content/docs/**, which the lane table anchors todomain:devx(#6023) — the deliverable's landing site, not the subject's domain. ⛔ This seat does not setdomain:*; 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).