From 5f409db97370cf6e52dc43c015918c35a446515f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 04:35:40 +0000 Subject: [PATCH] fix(app-shell): the fallback email-template form stops offering the retired category and isSystem keys The metadata admin's fallback schemas offered `email_template.category`, `email_template.isSystem` and the spec-17 tombstone `skill.triggerPhrases`. The spec retires the first two (ADR-0049 enforce-or-remove, the objectui half of objectstack-ai/objectstack issue 22876) and already refuses the third, so a form built from the fallback could write a key the server refuses. A current server serves its own schema for both types, which the edit page reads first, so the visible form is unchanged there. The file header said the fallback was used for every type; it now says when it is used. Claude-Session: https://claude.ai/code/session_019G5ZnRrTMiwcHG6iZM19zf Co-authored-by: Claude --- .../22876-email-template-fallback-keys.md | 11 ++++++ .../views/metadata-admin/default-schemas.ts | 37 ++++++++----------- 2 files changed, 27 insertions(+), 21 deletions(-) create mode 100644 .changeset/22876-email-template-fallback-keys.md diff --git a/.changeset/22876-email-template-fallback-keys.md b/.changeset/22876-email-template-fallback-keys.md new file mode 100644 index 0000000000..fecdb308a8 --- /dev/null +++ b/.changeset/22876-email-template-fallback-keys.md @@ -0,0 +1,11 @@ +--- +'@object-ui/app-shell': patch +--- + +The Studio fallback form for an email template no longer offers `category` or `isSystem`, and the fallback skill form no longer offers `triggerPhrases` (objectstack-ai/objectstack#22876). + +`@objectstack/spec` retires `email_template.category` and `email_template.isSystem` (ADR-0049 enforce-or-remove): nothing ever read either key, so the spec refuses both with a migration note. `skill.triggerPhrases` was retired the same way in spec 17. The metadata admin's fallback schemas (`default-schemas.ts`) still offered all three, so against a server that serves no schema for the type, the form could write a key the server refuses. + +A current server serves its own schema for both types, and the edit page reads that schema before the fallback one. So against a current server the form is unchanged. The file's header comment, which said the fallback is used for every type, now says when it is used. + +Nothing is added or removed on the package entry. diff --git a/packages/app-shell/src/views/metadata-admin/default-schemas.ts b/packages/app-shell/src/views/metadata-admin/default-schemas.ts index 8558a83d85..31c0b803f2 100644 --- a/packages/app-shell/src/views/metadata-admin/default-schemas.ts +++ b/packages/app-shell/src/views/metadata-admin/default-schemas.ts @@ -1,10 +1,15 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. /** - * default-schemas — minimal JSONSchemas used by SchemaForm when the - * framework's `/meta/types` registry row doesn't carry a `schema` field - * (i.e. for every type today — full Zod→JSONSchema generation in the - * framework is a deferred milestone). + * default-schemas — minimal JSONSchemas used by SchemaForm ONLY when the + * framework's `/meta/types` registry row carries no `schema` field. The + * framework derives that field from each type's Zod schema (and keeps a + * hand-crafted fallback for a type whose schema does not derive), so against + * a current server the served schema wins and the entry here is not read: + * `ResourceEditPage` takes `entry.schema` first and `defaultSchema` second. + * What an entry here still decides is the form shown against a server that + * serves no schema for the type — so an entry must never offer a key the + * spec has retired, because the save would send it and be refused. * * These schemas cover the universal metadata header (name/label/ * description/scope) plus the small set of per-type "obvious" fields @@ -12,10 +17,6 @@ * edited via the raw JSON escape hatch — the schema is intentionally * lax (no `additionalProperties: false`) so unknown payload keys round- * trip untouched. - * - * When the framework starts emitting JSONSchemas in the registry, this - * file becomes a no-op (SchemaForm receives the real schema and ignores - * `defaultSchema`). */ import { registerMetadataResource } from './registry.js'; @@ -165,12 +166,9 @@ const SCHEMAS: Record> = { description: "Agent surface this skill binds to (ADR-0063).", enum: ['ask', 'build', 'both'], }, - triggerPhrases: { - type: 'array', - title: 'Trigger Phrases', - description: 'Natural-language phrases that activate this skill.', - items: { type: 'string' }, - }, + // No `triggerPhrases`: retired in spec 17 (objectstack#3896) — the + // phrases were never matched against anything, and the spec now refuses + // the key with a migration note. triggerConditions: { type: 'array', title: 'Trigger Conditions', @@ -307,12 +305,10 @@ const SCHEMAS: Record> = { required: ['name', 'label', 'subject', 'bodyHtml'], properties: { ...headerProps, - category: { - type: 'string', - title: 'Category', - enum: ['auth', 'notification', 'workflow', 'marketing', 'custom'], - default: 'custom', - }, + // No `category` and no `isSystem`: both are retired from the spec's + // `EmailTemplateDefinitionSchema` (objectstack-ai/objectstack#22876, + // ADR-0049 enforce-or-remove). Nothing ever read either one, and a + // fallback form that offered them would write a key the server refuses. locale: { type: 'string', title: 'Locale', default: 'en-US', description: 'BCP-47 tag (en-US, zh-CN, …)' }, subject: { type: 'string', title: 'Subject', description: 'Supports {{var.path}} interpolation' }, bodyHtml: { type: 'string', title: 'HTML Body', format: 'multiline' }, @@ -321,7 +317,6 @@ const SCHEMAS: Record> = { fromOverride: { type: 'object', title: 'From Override' }, replyTo: { type: 'string', title: 'Reply-To' }, active: { type: 'boolean', title: 'Active', default: true }, - isSystem: { type: 'boolean', title: 'System Template', default: false }, }, }, };