Skip to content

fix(metadata-protocol): draft preview no longer reports itself invalid over its own _draft badge - #8179

Merged
huangyiirene merged 3 commits into
mainfrom
claude/issue-7656-draft-preview-diagnostics
Aug 12, 2026
Merged

huangyiirene merged 3 commits into
mainfrom
claude/issue-7656-draft-preview-diagnostics

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes #7656

The defect, reproduced

GET /api/v1/meta/{type}/{name}?preview=draft answered _diagnostics.valid:false
for a valid draft, complaining about a key the read itself had just added:

Unrecognized key(s) on this object: `_draft`. Until #4001 closed this shape these
were dropped silently on the PARSE path — ...

Confirmed on origin/main before any edit, on both injection sites, with
tests that were red first (see "Reverse verification" below).

Root cause

The preview read stamps _draft:true onto the item so the console can badge it —
protocol.ts:4462 (list overlay) and protocol.ts:4672 (single-item read) — and
then hands the item to decorateMetadataItem → computeMetadataDiagnostics,
which re-parses it against the closed item schema.

That re-parse stripped only _diagnostics, via a private one-key helper
(stripDiagnostics) that predated _draft joining the shared
METADATA_READ_DECORATIONS list. So the reader validated its own badge and
reported the document invalid for it. The verdict described the reader, not the
document — and it reached every draft of every type, on both exits.

The fix

computeMetadataDiagnostics now calls the shared stripReadDecorations instead
of its private copy. One line of behaviour; the rest of the diff is the comment
explaining why the list is the right authority here.

This is the shape the codebase already owns. The module header of
spec/kernel/metadata-read-decorations.ts names two classes of consumer that
must strip: the write path's verbatim persist (#4326) and any re-parse of a
served document
(cloud#971's cold-boot flow bind). Read-time diagnostics are a
re-parse of a served document in exactly that sense — the third consumer — so it
reads the list rather than keeping a private subset of it.

Same class as the closed #6810 (indexed, rejected by name on a served object),
different remedy, deliberately: indexed did not belong on the served body
at all and was removed at its injection site, whereas _draft is the preview
badge the UI reads and is already a declared read decoration. Removing the stamp
would break the badge; the list is where it is consumed.

⛔ The item schema is not loosened. _draft stays rejected by name in a
stored body — pinned by a test — which is what keeps the #4326 write-path strip
load-bearing rather than cosmetic.

Scope note

The declared file surface was protocol.ts — "the draft-preview read decoration
and the _diagnostics computation it feeds". The fix landed in the module that
is that computation (metadata-diagnostics.ts, same package), not in
protocol.ts. Closing it there fixes both injection sites with one edit, covers
any future decoration key for free, and touches none of protocol.ts — which is
carrying two other claimed regions this round (#8136, #8003).

Tests

packages/metadata-protocol/src/protocol.read-decorations.test.ts, +6 cases in
the file that already owns this discipline:

  • the reproduction, both exits — a valid draft read back through
    getMetaItem({ previewDrafts: true }) and through the getMetaItems draft
    overlay: _diagnostics.valid is true and no error mentions _draft.
  • anti-vacuity, both exits — a genuinely broken draft (a field whose type
    is not a field type, seeded directly since the save path refuses it with 422)
    still reads back valid:false, with errors naming amount and not
    _draft. Without these, a fix that simply stopped computing diagnostics on
    the draft path would pass.
  • drift guard — every member of METADATA_READ_DECORATIONS must be
    invisible to the verdict, so a fourth decoration fails on a unit here instead
    of as valid:false on somebody's badge.
  • anti-loosening pin — the object schema still rejects _draft with
    unrecognized_keys.

Reverse verification

Reverting only metadata-diagnostics.ts to origin/main turns 5 of the 6
new cases red, each on the card's verbatim message. The sixth — the
anti-loosening pin — is green in both directions by design: it pins a
constraint the fix must not relax (the schema stays closed), not the fix itself,
so a direction change there would mean the schema had been loosened.

Evidence

@objectstack/metadata-protocol   Test Files  75 passed (75)   Tests 1100 passed (1100)
@objectstack/objectql            Test Files 191 passed (191)  Tests 3390 passed (3390)
@objectstack/rest                Test Files 102 passed (102)  Tests 1728 passed (1728)
@objectstack/runtime             Test Files 145 passed (145)  Tests 2195 passed (2195)
@objectstack/metadata            Test Files  31 passed (31)   Tests  603 passed (603)
@objectstack/service-automation  Test Files  79 passed (79)   Tests  940 passed (940)

Consumer direction: the five non-authoring packages above are downstream
consumers of @objectstack/metadata-protocol (prefix filter ... + the package
name), picked as the ones whose suites exercise /meta reads, draft preview or
_diagnostics. Type surface is unchanged, so this sweep is about behaviour pins,
not types.

Gates named by scripts/pm/dispatch-gates.mjs for these files, all green
locally: check:error-code-casing, check:cross-package-test-inputs,
check:durability-log-level, check:changeset-gate-self-tests,
check:objectui-changeset, check-changeset-no-major, plus check:nul-bytes
and eslint on the changed files.

Changeset: .changeset/draft-preview-diagnostics-draft-badge.md (patch).


Generated by Claude Code

@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 12, 2026 6:45pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata-protocol.

3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-protocol)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/metadata-protocol)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/metadata-protocol)

⛔ 1 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/v9.mdx (via @objectstack/metadata-protocol)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants