Skip to content

rest: the GENERIC declared-status passthrough still disagrees on object between the two error doors — plus one bespoke arm (RECORD_NOT_FOUND) still reachable from one door only #14725

Description

@os-trump

Two residues of the #14541 door-disagreement class that #14541 does not close, filed rather than ridden on its PR: one was flagged by the contract review as out of scope ("noted for a card rather than as a condition"), the other was found by the drift guard that review's condition 3 required, and both are the same visible symptom with one decision behind them.

Residue 1 — the generic passthrough (contract-review probe H)

After #14541 the two doors agree for every error a bespoke arm classifies. They still disagree for an error that reaches the generic declared-status passthrough, because the two copies of that passthrough differ by one key:

  • classifyDataError's copy ends ...(object ? { object } : {}) — it appends the object name the door was called with.
  • resolveErrorResponse's 4xx arm has no such limb.

Measured on the #14541 branch, one error object, both doors:

error = { code: 'DUPLICATE_RECORD', status: 409 }      // no `name`, so no bespoke arm
  mapDataError(err, 'duly_note')     409 {"error":"…","code":"DUPLICATE_RECORD","object":"duly_note"}
  sendThrownError(res, err, 'duly_note')  409 {"error":"…","code":"DUPLICATE_RECORD"}

Same class as #14541 — one refusal, two bodies, decided by which route caught it — one arm over.

Residue 2 — RECORD_NOT_FOUND is still a one-door arm

packages/rest/src/error-response.ts's record-level not-found arm sits BELOW the shared classification #14541 introduced:

if (error?.code === 'RECORD_NOT_FOUND' || /^Record\s+\S+\s+not found in\s+\S+/i.test(raw)) {
    return { status: 404, body: { error: raw, code: 'RECORD_NOT_FOUND', ...(object ? { object } : {}) } };
}

Its producer declares a status, so the #14541 defect reaches it exactly as it reached the other ten: packages/core/src/utils/record-not-found.ts's recordNotFoundError sets code = 'RECORD_NOT_FOUND', status = 404 and object. So on every route reporting through handleRouteError / sendThrownError the declared-status passthrough answers first and object is dropped, while the single-record /data door reaches the arm and ships it.

It was not lifted with the other arms in #14541 for two reasons worth recording rather than rediscovering:

  1. Its second limb is gated on message TEXT (/^Record … not found in …/i over the computed raw), and Routes exiting through handleRouteError answer the engine's DUPLICATE_RECORD envelope from resolveErrorResponse's .status passthrough — field and object dropped, mapDataError's structured 409 arms never consulted #14541's stated boundary for the shared classification is declared code only — lifting a text sniff above the passthrough is what resolveErrorResponse's own docblock argues against.
  2. Routes exiting through handleRouteError answer the engine's DUPLICATE_RECORD envelope from resolveErrorResponse's .status passthrough — field and object dropped, mapDataError's structured 409 arms never consulted #14541's wire delta was measured, published and contract-reviewed over a fixed set of codes. Adding an eleventh body change after that verdict would put an unreviewed delta into the PR whose whole claim is that the review saw every one.

It is named in that PR's drift guard as a known-gap entry citing this card, so the guard is green by disclosure rather than by omission.

The one decision behind both

Should the bulk / metadata / UI door's declared-status passthrough carry object?

Not claimed

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions