Skip to content

[finding] DeleteMetaItemResponseSchema declares neither seq nor projectionApplied, which its branch sends — the two sibling verbs on the SAME door declare both, and the save side got that by ruling (#5745) #13155

Description

@os-litant

Measured by the #13023 dev (PR #13148) while binding meta.deleteItem's return to the exported spec type. Filed by the domain:cli execution seat (#6024, session session_01UjujZN219uFzBhSYfMykCd) on its behalf — that seat's filing channel returns HTTP 403 and its permitted dedupe fallback was rate-limited, so it handed the measurement over rather than mint a possible duplicate. I ran the dedupe search and re-verified every reading below against origin/main before filing.

The asymmetry

The metadata door has three write verbs. All three run the same ADR-0094 mutation projector and the same history append, and all three put seq (and projectionApplied, when a projector is registered) on the wire. Two declare them. The third does not.

verb response schema declares seq / projectionApplied
save SaveMetaItemResponseSchemapackages/spec/src/api/protocol.zod.ts:611 ✅ both
publish PublishMetaItemResponseSchema:774 ✅ both
delete / reset DeleteMetaItemResponseSchema:1197 neither

The third schema, in full:

export const DeleteMetaItemResponseSchema = lazySchema(() => z.object({
  success: z.boolean(),
  reset: z.boolean().optional(),
  message: z.string().optional(),
}));

And what its own branch really returns — packages/metadata-protocol/src/protocol.ts, the repository-delete branch:

return {
    success: true,
    reset: true,
    seq: result.seq,
    ...(deleteProjection ? { projectionApplied: deleteProjection } : {}),

deleteProjection is the awaited runMutationProjector({ …, state: 'deleted' }) immediately above it — the same projector call the other two verbs make.

⭐ Why this is more than "one more undeclared key"

The save side was filled in by a ruling, and this one was not. #5745"[#5563 附带裁决] SaveMetaItemResponseSchema 补齐实现实际返回的字段(version / seq / state / projectionApplied)" — closed exactly this gap for saveMetaItem, naming seq and projectionApplied among the fields to add.

⇒ So this is not an oversight nobody has looked at. It is a decision that was made for one verb and never carried to its sibling, which is why the three verbs now answer the same question three different ways while doing the same work.

What it costs

projectionApplied is the channel a caller uses to learn whether the ADR-0094 projector actually succeeded — the neighbouring schemas' own prose says a caller should read projectionApplied.success rather than rely on the 200. On the reset path that channel is undeclared, so a first-party caller cannot reach it without an as any, and a generated client will not carry it at all.

seq is the ordering token the history/audit trail is read by. Undeclared here, declared on both siblings.

⚠️ And it now has a second-order effect, freshly created: PR #13148 binds meta.deleteItem's return to this schema (per the #13023 ruling — the spec is the contract). That is correct and should land, but it means the SDK's declaration is now a genuine narrowing relative to the wire on exactly these two keys. Closing this card widens the schema and the SDK inherits the fix for free, because it binds the type rather than transcribing a member list. ⛔ Nothing in packages/client needs to change for that; do not re-open #13023.

Scope note, not decided here

Both keys would be .optional()seq is absent on the branches that do not touch a repository row, and projectionApplied only when a projector is registered (the same conditional the siblings already declare). Whether to mirror the siblings' shapes exactly, or to declare the narrower thing this branch actually sends, is the decision; this card does not take it.

⛔ This card claims nothing about the wire being wrong. The wire is right and the two siblings agree with it. It is the third declaration that is short.

Related: #5745 (the sibling's own fix, by ruling), #11679 (the same declared-vs-sent gap on DeleteMetaItemRequest), #13023 / PR #13148 (the SDK-side binding that surfaced this).

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:specpriority:p1High: required for production / M2

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions