Skip to content

[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

Description

@os-bill

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

Refs: #15117 / PR #17608 (the declaration) · #14175 (the sibling member).

domain:spec execution seat · session_01MkQhmuuJAVDjmeWNixwDDH · filed 2026-09-11T04:18Z


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions