Found while measuring the read-seam census for #8845 (measurement card; no fix attempted there). Filed unassigned. Not a claim.
Measured on origin/main @ 8664a2c.
The seam
packages/objectql/src/engine.ts, in cascadeDeleteRelations() (catch at :9896):
letdependents: any[];try{dependents=awaitthis.find(childName,{where: {[fieldName]: id}, context }asany);}catch{continue;}if(!dependents||dependents.length===0)continue;if(behavior==='restrict'){// ... refuse the delete with DELETE_RESTRICTED}The continue is reached whenever the dependents probe fails for any reason. Control then moves to the next child relation, and the effect is exactly as if the probe had returned zero rows:
behavior === 'restrict' never fires, so a delete that the integrity rules say must be refused is allowed through;behavior === 'set_null' / 'cascade' never runs, so child rows that should have been nulled or removed are left orphaned;- nothing is logged and nothing is returned to the caller, so the delete reports success.
This is fail-OPEN on a referential-integrity guard. The comparable seams in the same family fail closed or report.
Why it is not caught today
check:durability-log-level's read-seam invention rule classifies a catch by the expression it returns. This one returns nothing — it jumps — so there is no expression to classify and the seam is counted in the census and cleared as no invented answer. That blind spot is #8845's subject; #8845 measured it and deliberately did not extend the rule (the reasons are recorded in the checker's header). So this seam needs fixing on its own terms, not by waiting for a gate.
Suggested shape
The repo already has the vocabulary for this: discriminate the error's type and only treat the benign case as "no dependents".
}catch(error){if(isMissingTableError(error))continue;throwerror;}A child table that has not been provisioned genuinely has no dependents, so continue is truthful there. Any other failure means the guard could not be evaluated, and a referential-integrity guard that could not be evaluated must not silently pass.
Notes
Found while measuring the read-seam census for #8845 (measurement card; no fix attempted there). Filed unassigned. Not a claim.
Measured on
origin/main@8664a2c.The seam
packages/objectql/src/engine.ts, incascadeDeleteRelations()(catch at:9896):The
continueis reached whenever the dependents probe fails for any reason. Control then moves to the next child relation, and the effect is exactly as if the probe had returned zero rows:behavior === 'restrict'never fires, so a delete that the integrity rules say must be refused is allowed through;behavior === 'set_null'/'cascade'never runs, so child rows that should have been nulled or removed are left orphaned;This is fail-OPEN on a referential-integrity guard. The comparable seams in the same family fail closed or report.
Why it is not caught today
check:durability-log-level's read-seam invention rule classifies acatchby the expression it returns. This one returns nothing — it jumps — so there is no expression to classify and the seam is counted in the census and cleared asno invented answer. That blind spot is #8845's subject; #8845 measured it and deliberately did not extend the rule (the reasons are recorded in the checker's header). So this seam needs fixing on its own terms, not by waiting for a gate.Suggested shape
The repo already has the vocabulary for this: discriminate the error's type and only treat the benign case as "no dependents".
A child table that has not been provisioned genuinely has no dependents, so
continueis truthful there. Any other failure means the guard could not be evaluated, and a referential-integrity guard that could not be evaluated must not silently pass.Notes
return, so acatchthat degrades by FALLING THROUGH into an empty accumulator is structurally invisible #8845 census turned up, this is the only one where the invented answer disables an authorization/integrity refusal rather than shortening a report.return, so acatchthat degrades by FALLING THROUGH into an empty accumulator is structurally invisible #8845 (the measurement),check:durability-log-level结构性看不见「读接缝把故障答成空值」这一类 —— #4825 / #5108 全家都在闸门盲区里 #5186 (the rule), ObjectQL.delete's single-id cascade is not transactional — a refusal mid-cascade leaves earlier children deleted while the response says the delete failed #7413 and DELETE_RESTRICTED (409) message is shown verbatim to end users: English-only, leaks API names, and contains developer-facing advice #7307 (prior cascade-delete work on this function, both closed and neither touching this path).