feat(metadata): draft/package lifecycle for publish-as-preview (overlay reads, teardown, discard, delete)#1569
Merged
Conversation
…review
ADR-0033's loop is build(draft) -> review -> publish, but review was only a
JSON diff; the rendered object page / kanban / form / nav that actually
confirms a change only existed AFTER publish. This adds a request-scoped
draft-overlay read mode so an (admin) reviewer can render the console off
pending drafts before publishing:
- getMetaItems({previewDrafts}) overlays state='draft' rows on active (draft
wins; draft-only surfaces; never hydrates the SchemaRegistry).
- getMetaItem({previewDrafts}) is non-strict: draft if present, else active
(vs strict state:'draft' which 404s no_draft).
- overlaid items tagged _draft:true for UI badging.
- dispatcher threads ?preview=draft on GET /metadata/:type[/:name].
Admin gating of the flag is a deliberate follow-up (step 2). The same overlay
also unblocks the AI agent referencing its own drafts (follow-up).
Tests: protocol-meta draft-overlay (draft wins, draft-only, _draft, getMetaItem
fallback) + full objectql sweep green (509).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Object storage was create-only: publish creates a table, but deleteMetaItem
only tombstones the metadata row, leaving the physical table behind. That made
"publish an object just to preview it with data, then discard" leave residue.
- engine.dropObjectSchema(name): inverse of syncObjectSchema; calls the driver's
existing dropTable.
- deleteMetaItem({dropStorage}): opt-in, DESTRUCTIVE, guarded — object + active
only, never sys_; default false keeps delete non-destructive. Best-effort.
- REST: DELETE /meta/:type/:name?dropStorage=true.
Makes "publish to preview -> discard" cleanly reversible (the chosen approach:
lean on publish-into-dev for data confirmation, made safely undoable).
Tests: deleteMetaItem teardown (drops for object+active; not by default; not
sys_; not non-object) + objectql sweep green (513).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| }); | ||
|
|
||
| it('does not drop storage for a non-object type even with dropStorage', async () => { | ||
| const { engine, rows } = makeStubEngine(); |
…rd / delete) Two distinct package-level operations on the per-item delete primitive: - discardPackageDrafts(packageId): drop only pending DRAFT rows, revert to the published baseline. NON-destructive (active metadata + tables untouched). "I edited this app a while, it's worse than before — abandon all changes." sys_metadata path (no metadata-service dep, unlike POST /packages/:id/revert). REST: POST /packages/:id/discard-drafts. - deletePackage(packageId): remove ALL package rows (active + draft) + tear down each object's table by default (DESTRUCTIVE; keepData:true preserves tables, sys_ guard still applies). "I don't want this package anymore." DELETE /packages/:id now also does this persisted removal (previously only the in-memory registry unregister, leaving AI-package rows + tables behind); ?keepData=true opts out of teardown. Drafts deleted before active so each table is dropped once; per-item failures collected without aborting. Tests: orchestration for both + objectql sweep (519). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…kageId (Fix 4) Two gaps that broke the multi-step "build app -> author a flow for it" path (found verifying the solution_design guardrail): 1. AI couldn't discover its own draft objects: list_objects/list_metadata read getMetaItems active-only, so a just-drafted object was "not found" when the agent then authored a flow against it. They now pass previewDrafts:true (older runtimes ignore the flag -> stay active-only). describe was already draft-first. 2. The auto-authored flow had no package to bind to: apply_blueprint now surfaces a top-level packageId + bindingHint so the agent passes it to create_metadata and the flow lands in the app package, not an orphan draft. Makes the guardrail's "model data, then proactively draft the approval flow bound to the app" executable end-to-end. service-ai suite green (ai-service embedder test fails only locally — env-dependent, untouched). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backend for the draft/package lifecycle behind "publish-as-preview" (ADR-0033 review loop) — drafts as a first-class state for both humans and the AI. Five composable capabilities, each independently tested.
1. Draft-overlay reads (
previewDrafts)Render the console (or let the AI discover) pending drafts before publish.
getMetaItems/getMetaItemoverlaystate='draft'on active (draft wins; draft-only surfaces;_draft:truetag); dispatcher threads?preview=draft.2. Storage teardown on delete (
dropStorage)Object storage was create-only — delete left an orphan table.
engine.dropObjectSchema→ driverdropTable;deleteMetaItem({dropStorage})DESTRUCTIVE/opt-in, gated (object+active only, neversys_);DELETE /meta/:type/:name?dropStorage=true.3.
discardPackageDrafts— abandon edits, revert to baselineNON-destructive: drops only draft rows.
POST /packages/:id/discard-drafts. "Edited a while, it's worse — abandon all changes."4.
deletePackage— remove an unwanted package entirelyDESTRUCTIVE: all package rows + object tables (
keepData=truepreserves tables).DELETE /packages/:idnow does this persisted removal (was registry-only). "Don't want this package anymore."5. AI authoring is draft-aware + package-aware (Fix 4)
Found while verifying the process guardrail:
list_objects/list_metadatawere active-only → the agent couldn't find an object it just drafted when authoring a flow for it. Now passpreviewDrafts:true(reusing Add metamodel interfaces for ObjectQL/ObjectUI contract #1, the unifying mechanism).apply_blueprintnow surfaces a top-levelpackageId+bindingHintso the agent binds the follow-up flow to the app package instead of orphaning it.Why this shape (design note)
True data preview of a brand-new draft object is hard (no table until publish; the platform had no drop-table teardown at all). Chosen approach: cheap draft-overlay for structural/AI discovery, and lean on publish (into a dev sandbox) for data-level confirmation — made safe by reversible item teardown + package discard/delete. Admin-gating
?preview=draftis a deliberate follow-up. Seedocs/notes/draft-overlay-preview-plan.md.Tests
protocol-meta(overlay),protocol-publish-rollback(teardown),protocol-package-lifecycle(discard/delete),metadata-tools+blueprint-tools(Fix 4). Fullobjectqlgreen (519);service-aigreen (one pre-existing env-dependent embedder test aside). Dispatcher/rest typecheck clean.Pairs with objectui#1472 (Discard/Delete buttons) and framework#1570 (process guardrail).
🤖 Generated with Claude Code