Skip to content

Two more faces of the DESTRUCTIVE_CHANGE 409 prescribe ?force=true on routes that never thread it — the compound-name PUT /meta/:type/:a/:b and the runtime dispatcher PUT /meta #11095

Description

@os-zhuang

Measured while repairing the remedy clause on the duplicate face for #11015. Separate defect, filed rather than fixed in that PR — the repair there is not obviously the repair here.

What was measured

saveMetaItem's Phase 3a-destructive gate raises the 409 DESTRUCTIVE_CHANGE in one place and the clause is quoted onto whatever response the caller's catch builds. #11015 made that clause face-aware and repaired the one face it was filed on (duplicatePackage's failed[].error). The face inventory in packages/metadata-protocol/src/protocol.destructive-409-face-inventory.test.ts lists two further doors that reach the same gate and also never thread force, and both were re-measured on origin/main @ 4257e4e:

face call site threads force?
@objectstack/rest PUT /meta/:type/:name packages/rest/src/rest-server.ts:5472 yes...(force ? { force: true } : {})
@objectstack/rest PUT /meta/:type/:a/:b (compound name) packages/rest/src/rest-server.ts:6590 no — the request is built field by field and force is not one of them
@objectstack/runtime dispatcher PUT /meta packages/runtime/src/domains/meta.ts:417 nosaveMetaItem({ type, name, item, organizationId, ...(packageId ? { packageId } : {}) })

So a caller refused on either of the bottom two rows is told — re-submit with ?force=true to proceed. and, doing exactly that, gets the identical refusal back. Same defect class as #11015, different doors.

Why this was not folded into #11015's PR

#11015's duplicate face had a genuine alternative to prescribe (duplicate into a free target namespace, or reconcile the collision first), so repairing the message was the whole fix and widened nothing. These two doors have no such alternative: they address one item by name, and the only thing that lifts a risk-acknowledgement refusal is the acknowledgement. The two candidate repairs are therefore

Both are defensible and the choice is not the dev seat's to make, which is why this is filed rather than folded.

Where the repair would land

packages/metadata-protocol/src/protocol.ts already carries the mechanism #11015 added — destructiveChangeRemedy(face, name) plus a server-stated writeFace on the saveMetaItem request — so option B is a new face value and two call sites stating it. Option A is a change to packages/rest/src/rest-server.ts and packages/runtime/src/domains/meta.ts. The ⚠️ paragraph on destructiveChangeRemedy's docblock and the [#11015] section of the face-inventory test both record these two rows as knowingly left, and point here.

Related: #11015 (the duplicate face, fixed), #10886 (the sole-carrier verdict that forbids trimming the findings prose).

Measured on origin/main at 4257e4e.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions