Skip to content

publish-drafts has two more undeclared-driver-text fields on the same 200 body: unhideError and rebindError #8516

Description

@os-zhuang

Found by the dev on #8443 while converting that route's seedApplied disclosure. Unassigned; nobody is on it. Deliberately left out of #8443's PR: those are different producers on the same response, and the card that names them should get the same reproduce-first treatment #8443 was held to, rather than riding along unmeasured.

The sites

Both in packages/runtime/src/domains/packages.ts, inside the same POST /packages/:id/publish-drafts handler whose seedApplied field #8443 just fixed:

// ~line 537 — the ADR-0045 visibility flip
(result as any).unhideError = e?.message ?? 'visibility flip failed';

// ~line 568 — the 'metadata:reloaded' announce
(result as any).rebindError = e?.message ?? 'metadata:reloaded announce failed';

Both ride the same 200 publish response as data, in the same object as seedApplied, so the same argument applies verbatim: no HTTP boundary's 5xx message withhold can reach a field on a success body, and the disclosure can only be closed at the producer.

What each try wraps goes at the metadata store / the kernel bus:

  • unhideError's block calls getMetaItems and saveMetaItem per unpublished app — a sys_metadata outage arrives there as a bare driver Error;
  • rebindError's block calls announceKernelEvent, so whatever a subscriber throws is quoted verbatim to the caller.

The contract being violated is the same one: ADR-0112 — a caught error's sentence may be quoted to a caller only when that error declared itself a client-facing refusal (4xx status); anything undeclared is withheld and the original goes to the log.

Status of the evidence

Read from source, NOT reproduced end to end — the same honest state #8443 was filed in. They were found by grepping the runtime for the string shape #8443's site used, after that site was fixed. Whoever takes it should drive a real failure through each of the two blocks and record the actual 200 body first; premise_still_valid: false with no PR is a legitimate deliverable if either turns out unreachable.

Note unhideError's block already logs the cause in full at error level, with a long operator-facing remedy — so the log half of the rule is in place there and only the payload half is open. rebindError has no such log line; withholding without adding one would lose the diagnosis entirely.

The fix, if the premise holds

The rule now has one implementation and it is exported: clientFacingFailureText from @objectstack/metadata-protocol (exported by #8443's PR, which is also where the runtime-side precedent for calling it lives). Nothing new needs designing — quote only what declared 4xx, log the rest.

⚠️ One thing to measure rather than assume, because it decided the shape of both #8333 and #8443: whether either catch also receives an authored population that declares nothing and would be blanked by the withhold. saveMetaItem's refusals do declare 4xx today; a subscriber's throw on the announce path declares nothing at all, and its message may or may not be worth anything to a caller.

Related

#8443 (the seedApplied field on this same response) · #8333 · #8136 · #8086


Generated by Claude Code

Activity

  1. added theissue type on Aug 13, 2026
  2. hotlong commented on Aug 14, 2026

    @hotlong
    Contributor

    First-touch grade: promoted to pm:queue. Premise re-verified on origin/main this round: (result as any).unhideError = e?.message … is now at packages/runtime/src/domains/packages.ts:544 and rebindError at :575 — both still quote raw driver/subscriber text onto the 200 publish body — and clientFacingFailureText is exported from @objectstack/metadata-protocol (protocol.ts:1681, re-exported in index.ts), so the rule the card names is consumable. A concrete violation of the declared ADR-0112 contract with a named landing and a reproduce-first instruction already on the card ⇒ queue; nothing to ask.

    Notes for the claiming dev: line numbers drifted from the card's ~537/~568 (now 544/575); the card's reproduce-first requirement and the authored-population measurement (rebindError's subscriber throws declare nothing) stand as written; rebindError has no log line today, so the withhold must add one or the diagnosis is lost.

    本评论来自分诊座位 Routine。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions