You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(metadata): draft-overlay reads (previewDrafts) for pre-publish preview
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>
* feat(metadata): optional storage teardown on delete (dropStorage)
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>
* feat(packages): discardPackageDrafts + deletePackage (one-click discard / 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>
* fix(ai): authoring tools see their own drafts; blueprint surfaces packageId (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>
---------
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
fix(ai): authoring tools can see their own drafts; blueprint surfaces the package to bind to
6
+
7
+
Two gaps that broke the multi-step "build app → author a flow for it" path (found while verifying the new solution_design guardrail):
8
+
9
+
1.**The agent couldn't discover its own draft objects.**`list_objects` / `list_metadata` read `getMetaItems`**active-only**, so a brand-new object the agent had just drafted (never published) was reported as "not found" when it then tried to author an approval flow against it. They now pass `previewDrafts: true`, overlaying pending drafts on the active list (older runtimes ignore the flag → stay active-only). `describe_metadata` was already draft-first.
10
+
11
+
2.**The auto-authored flow had no package to bind to.**`apply_blueprint` already homes its artifacts in an app package, but its result only nested the id under `package`. It now also surfaces a top-level `packageId` and a `bindingHint` telling the agent to pass that `packageId` to `create_metadata` when it drafts follow-up automation (e.g. the approval flow) — so the flow lands in the app package instead of becoming an orphan draft.
12
+
13
+
Together with the solution_design process guardrail, this makes the "model the data, then proactively draft the approval flow bound to the app" flow actually executable end-to-end.
feat(metadata): optional storage teardown on delete so "publish to preview" leaves no orphan table
7
+
8
+
Object storage was create-only: `publishMetaItem` creates a table (`ensureObjectStorage`) but nothing ever dropped one — `deleteMetaItem` only tombstones the metadata row, leaving the physical table behind. That made the pragmatic "publish an object just to preview it with real data, then discard if wrong" loop leave residue.
9
+
10
+
Adds the inverse path, opt-in and guarded:
11
+
12
+
-`engine.dropObjectSchema(name)` — inverse of `syncObjectSchema`; resolves the table name + driver and calls the driver's existing `dropTable` (DROP TABLE IF EXISTS / drop collection).
13
+
-`deleteMetaItem({ …, dropStorage })` — when `true`, drops the object's physical table after the metadata is removed. **DESTRUCTIVE**, so it is gated: `object` type only (others have no table), `active` state only (drafts were never materialised), and never a `sys_`-prefixed platform table. Default `false` keeps delete non-destructive to data. Best-effort: a drop failure is logged, not thrown.
14
+
- REST: `DELETE /meta/:type/:name?dropStorage=true` threads the flag.
15
+
16
+
This makes "publish to preview → discard" cleanly reversible. Combined with the draft-overlay read mode, it backs the team's chosen approach: lean on publish (into a dev sandbox) for data-level confirmation rather than building a full draft-data preview, and make that publish safely undoable.
feat(metadata): draft-overlay reads so an admin can render the console off pending drafts before publish
7
+
8
+
ADR-0033's loop is `build (draft) → review → publish`, but "review" was only a JSON diff — the one thing that actually confirms an AI/hand-authored change (the rendered object page / kanban / form / nav) only existed *after* publish. That forces publishing unreviewed metadata just to look at it, defeating the draft gate.
9
+
10
+
This adds a request-scoped **draft-overlay read mode** to the metadata resolution layer:
11
+
12
+
-`getMetaItems({ …, previewDrafts })` — after the active overlay, overlays `state='draft'` rows on top (draft WINS on name collision; draft-only items surface too). Drafts are never hydrated into the process-wide SchemaRegistry.
13
+
-`getMetaItem({ …, previewDrafts })` — non-strict: prefers a draft row if one exists, else falls back to the active value (unlike the strict `state:'draft'` mode, which 404s `no_draft`).
14
+
- Every overlaid item is tagged `_draft: true` so the UI can badge it and show a "preview" banner.
15
+
- The runtime HTTP dispatcher threads `?preview=draft` on `GET /metadata/:type` and `GET /metadata/:type/:name` into these reads.
16
+
17
+
The same overlay also unblocks the AI authoring agent referencing its own just-drafted objects (a follow-up will point `list_metadata` at it). Admin gating of the `?preview=draft` flag is a deliberate follow-up step.
18
+
19
+
Note: a brand-new draft object has no physical table until publish, so preview renders its *shape* (form/view/kanban/nav) but shows no data; field-additions to existing objects preview fully.
feat(packages): one-click discard-drafts and full delete for a package
7
+
8
+
Two distinct package-level lifecycle operations, both built on the per-item delete primitive:
9
+
10
+
-**`discardPackageDrafts(packageId)`** — drop every pending DRAFT bound to the package, reverting it to its last published baseline. NON-destructive: active/published metadata and physical tables are untouched. Use case: "I edited this app for a while and it turned out worse than before — abandon all my changes." Routes through the sys_metadata path (no metadata-service dependency, unlike the existing `POST /packages/:id/revert`, which 503s without a metadata service). REST: `POST /packages/:id/discard-drafts`.
11
+
12
+
-**`deletePackage(packageId)`** — remove the ENTIRE package: every `sys_metadata` row (active + draft) and, by default, the physical table of each object it defined (DESTRUCTIVE). `keepData: true` removes metadata but preserves tables; the `sys_`-table guard still applies. Use case: "I don't want this package anymore." `DELETE /packages/:id` now performs this persisted removal in addition to the in-memory registry unregister it already did (previously it left AI/runtime packages' rows and tables behind); `?keepData=true` opts out of teardown.
13
+
14
+
Drafts are deleted before active rows so each object's table is torn down exactly once. Per-item failures are collected without aborting the rest.
0 commit comments