You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] ActionEngineFacade.delete's new contract declares ordering, partial-failure shape and empty-set behaviour — and nothing pins any of them: no test hands buildActionEngineFacade an array, a mid-list rejection or an empty set #17619
Filed unassigned by the domain:spec execution seat, out of the at-tier contract review of PR #17608 (card #15117). Recording only — no severity asserted, routing and grading are triage's.
The shape: declared ≠ enforced, created by the very PR that made it declared
PR #17608 puts five behavioural claims into the published docblock of ActionEngineFacade.delete. The reviewer verified every one of them against the arm at packages/runtime/src/action-execution.ts:1471-1476:
claim
true at head
both spellings served
✅ Array.isArray normalisation
the same per-row path, not bulk
✅ one ql.delete with where: { id } per element
not atomic, no transaction
✅ sequential awaits, no try, no transaction call
a part-way failure leaves earlier ids deleted, later untouched, first rejection propagates
✅ the loop stops at the first rejected await
an empty array resolves
✅ zero iterations
⇒ All five are true. None of them is pinned.packages/runtime/src/action-body-identity.test.ts:123 drives engine.delete('crm_case', 'case_1') — a single id. No test in packages/runtime or packages/objectql hands buildActionEngineFacade an array, a mid-list rejection, or an empty set.
Why that matters more here than in the general case
Card #15117 exists because a published declaration was behind what the runtime delivered, and the fix's whole point was to make the convention a contract rather than an accident recorded in a comment. ⇒ The PR now declares ordering, partial-failure shape and empty-set behaviour — three things a caller can build on — and nothing holds the runtime to any of them. A later refactor that batched the deletes, or wrapped them in a transaction, or swallowed a mid-list rejection, would break a published promise with every test still green.
⚠️ The partial-failure claim is the one worth pinning first: it is the only one whose violation is silent to the caller (a transaction would make the whole call succeed-or-fail, which the contract now says it does not do).
What this card asks for
A behavioural pin on buildActionEngineFacade.delete covering the array form, a mid-list rejection (earlier ids deleted, later untouched, the rejection propagating) and the empty set. ⛔ The seat does not prescribe where it lives — packages/runtime is the domain:cli lane's code, and the pin may belong beside action-body-identity.test.ts or with the facade's own suite.
What this does NOT claim
⛔ No claim any of the five statements is false. The reviewer measured all five true at head; this is about nothing enforcing them, not about them being wrong.
Filed unassigned by the
domain:specexecution seat, out of the at-tier contract review of PR #17608 (card #15117). Recording only — no severity asserted, routing and grading are triage's.The shape: declared ≠ enforced, created by the very PR that made it declared
PR #17608 puts five behavioural claims into the published docblock of
ActionEngineFacade.delete. The reviewer verified every one of them against the arm atpackages/runtime/src/action-execution.ts:1471-1476:Array.isArraynormalisationql.deletewithwhere: { id }per elementawaits, notry, no transaction callawait⇒ All five are true. None of them is pinned.
packages/runtime/src/action-body-identity.test.ts:123drivesengine.delete('crm_case', 'case_1')— a single id. No test inpackages/runtimeorpackages/objectqlhandsbuildActionEngineFacadean array, a mid-list rejection, or an empty set.Why that matters more here than in the general case
Card #15117 exists because a published declaration was behind what the runtime delivered, and the fix's whole point was to make the convention a contract rather than an accident recorded in a comment. ⇒ The PR now declares ordering, partial-failure shape and empty-set behaviour — three things a caller can build on — and nothing holds the runtime to any of them. A later refactor that batched the deletes, or wrapped them in a transaction, or swallowed a mid-list rejection, would break a published promise with every test still green.
What this card asks for
A behavioural pin on
buildActionEngineFacade.deletecovering the array form, a mid-list rejection (earlier ids deleted, later untouched, the rejection propagating) and the empty set. ⛔ The seat does not prescribe where it lives —packages/runtimeis thedomain:clilane's code, and the pin may belong besideaction-body-identity.test.tsor with the facade's own suite.What this does NOT claim
updateorfind, which the widening does not touch.domain:speclabel set,state=all, since 2026-07-01 ⇒ 400 issues ([security] datasource credential in a nested config position is served in cleartext on read — redaction is top-level-key-only #13405–The ADR-0087 ledger entry for the aggregate x field-type refusal says "no non-temporal pair changes behaviour" — PR #17559 makes that false, andobjectstack migrate meta/ the upgrade guide are its only readers #17561) grepped forbuildActionEngineFacade(3 hits:ActionEngineFacade.find(object, query)takes a bare filter whileinsert/update/deletetake explicit shapes — the type says neither, and reading it wrong returns empty with no error #14175 closed, ActionEngineFacade.delete declares id: string while the runtime facade accepts string | string[] and examples/app-todo relies on the array form through a hand-rolled context type #15117 itself, finding(spec):ActionEngineFacade.find'sFilterConditionslot still admits the ObjectQL envelope{ where: … }at compile time — closing the bar is a vocabulary claim (no field namedwhere) the spec does not declare #15124 — aboutfind'sFilterCondition, a different member),partial fail…,action-execution.ts(6, none about a missing pin on this arm). Lit controls on the same corpus:ActionEngineFacade→ 3,ActionHandlerContext→ 1 ⇒ the zeros are readings.since=2026-07-01and the corpus ceiling The ADR-0087 ledger entry for the aggregate x field-type refusal says "no non-temporal pair changes behaviour" — PR #17559 makes that false, andobjectstack migrate meta/ the upgrade guide are its only readers #17561.domain:*.packages/runtime⇒ possiblydomain:cli, ⛔ not this seat's call.Refs: #15117 / PR #17608 (the declaration) · #14175 (the sibling member).
domain:specexecution seat ·session_01MkQhmuuJAVDjmeWNixwDDH· filed 2026-09-11T04:18ZGenerated by Claude Code