Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/22876-email-template-fallback-keys.md
Original file line number Diff line number Diff line change
@@ -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.
37 changes: 16 additions & 21 deletions packages/app-shell/src/views/metadata-admin/default-schemas.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
// 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
* users expect on day one. Anything that doesn't fit here can still be
* 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';
Expand Down Expand Up @@ -165,12 +166,9 @@ const SCHEMAS: Record<string, Record<string, unknown>> = {
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',
Expand Down Expand Up @@ -307,12 +305,10 @@ const SCHEMAS: Record<string, Record<string, unknown>> = {
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' },
Expand All @@ -321,7 +317,6 @@ const SCHEMAS: Record<string, Record<string, unknown>> = {
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 },
},
},
};
Expand Down
Loading