Skip to content

[finding] metadata-protocol's batch verbs still put caught error text on client-facing payloads — the 8 producers option C did not reach #8333

Description

@os-zhuang

Filed by the dev on #8136 while landing option C of #8086. Unassigned; nobody is on it. This is the recorded remainder of that card's producer sweep, not a new discovery — the full inventory was enumerated there and only the measured cluster was fixed, deliberately and with the remainder named rather than silently narrowed.

Blocked-by: #8136 (its PR introduces the helper these sites would use).

What #8136 fixed, and what it did not

#8136 fixed the uninstall / overlay-delete cluster, which is the cluster #8130 reproduced end to end: deletePackage's first sys_metadata read, deleteMetaItem's two re-wrap exits, and the failed[] / cleanups[] arrays that ride onto a PACKAGE_DELETE_PARTIAL 400 inside details.

The rule it installed at the producer, stated once: a caught error's sentence is quoted back to a caller only when that error declared itself a client-facing refusal — a 4xx status in the ADR-0112 envelope. Everything else gets a stable sentence naming the operation, with the original error on cause for the log.

Eight sites in the same file were enumerated and not converted:

#SiteSink
P6publishPackageDraftsfailed[].errorbatch-publish response data
P7publish side effects materialize.failures[].errorsame
P8materializeApplied.error (feeds P7)same
P9seed-apply errorseed response data
P10duplicatePackagefailed[].errorcopy response data
P11revertCommitfailed[].errorrevert response data
P12revertToCommitfailed[].errorderivative of P11
P13migrateStoredMetadatarows[].reasonmigration report

Each reaches a client the same way the fixed ones do — as data on a response, not as a message — so no HTTP boundary's 5xx message withhold can reach any of them, which is the whole argument for option C over a fourth belt.

⚠️ Why this was NOT swept blind, and what the taker must measure first

This is the substantive part of the card, and it is a real design question rather than remaining typing.

Several of these sites carry authored refusals as well as driver text, and the two are not distinguishable by the sink. publishPackageDrafts' failed[].error is the clearest case: it ships alongside code and structured spec-validation issues, and its whole job is to tell an author which field of which draft is wrong. Applying the 4xx rule there without first measuring which publish-path refusals actually declare a status would blank exactly the authoring feedback #4277 exists for — a usability regression traded for a disclosure gain, on the surface AI-authored metadata apps depend on most.

So the first step is a measurement, not an edit:

  1. For each of P6–P13, drive the real path and record whether the errors arriving in that catch declare a 4xx status. Spec/Zod validation failures raised through saveMetaItem are the ones to check hardest — they are the population most likely to be authored-and-undeclared.
  2. Where refusals are undeclared but should be declared, the contract-first fix is to declare them at their own producer, not to loosen the rule at the collector. That is the same direction [finding] metadata-protocol interpolates raw driver text into client-facing messages — three downstream sanitizers each have a hole because of it (option C of #8086) #8136 took and it keeps the positive list intact.
  3. Only then convert the site.

A site whose refusals turn out to be uniformly undeclared-and-authored is a legitimate needs_decision, not a thing to force.

Two sites that look like members and are not

The copy path's the flow does not canonicalize: ... and conversion refused — ... strings interpolate authored schema-validation text, not driver text. They were examined and deliberately left alone. Whoever takes this should not "tidy" them in.

Evidence

Read from the file directly, structurally (${e.message}-shaped interpolation and direct assignment of a caught message into a payload field), never by grepping the strings the older cards quote — the producer #8086 originally named no longer exists and survives only as docblock prose. The sinks were confirmed by reading each method's return shape.

Not reproduced end to end per site. #8136 earned its premise with a live reproduction for the cluster it fixed; these eight are read from source, and whoever takes this should force a real driver failure through at least one of the batch verbs and record the actual response body before fixing, the same way #8086 and #8136 were each made to earn theirs.

Related

#8136 (option C, the measured cluster) · #8086 (the ruling recording option C) · #8130 · #8131 · #8132

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions