diff --git a/.changeset/prune-dead-capabilities-descriptor.md b/.changeset/prune-dead-capabilities-descriptor.md new file mode 100644 index 000000000..daa62d560 --- /dev/null +++ b/.changeset/prune-dead-capabilities-descriptor.md @@ -0,0 +1,32 @@ +--- +"@objectstack/spec": minor +--- + +feat(spec)!: remove the dead static capabilities-descriptor cluster (`ObjectQL`/`ObjectUI`/`Kernel`/`ObjectStack`/`ObjectOS CapabilitiesSchema`) (#1878 family) + +The "RUNTIME CAPABILITIES PROTOCOL" tail of `stack.zod.ts` — `ObjectQLCapabilitiesSchema`, +`ObjectUICapabilitiesSchema`, `KernelCapabilitiesSchema`, `ObjectStackCapabilitiesSchema`, +the deprecated `ObjectOSCapabilitiesSchema` alias, and all five inferred types — is +removed. Verified zero consumers repo-wide (framework, objectui apart from bare +re-exports, cloud, downstream-contract): it was never authorable (`defineStack` has +no such key), never registered, and never fed any endpoint. + +Worse than dead, it **lied**: the fixed-boolean self-portrait defaulted +`fieldLevelSecurity` / `rowLevelSecurity` / `auditLogging` / `backgroundJobs` to +`false` while every one of those is live and enforced on the platform, and +advertised `odataApi` which has never existed. An AI reading the schema would +build a systematically wrong model of the platform. + +**Migration — runtime capability discovery is dynamic, not a static schema:** + +| Removed | Live replacement | +| --- | --- | +| `KernelCapabilitiesSchema` booleans (`restApi`/`websockets`/`auditLogging`/…) | `GET /api/v1/discovery` — dynamic `capabilities` record with **declared === enforced** discipline (#3298: a capability is advertised only when the route is actually mounted AND the engine supports it) | +| `WellKnown`-style backend feature probes | `WellKnownCapabilitiesSchema` (`@objectstack/spec/api` discovery contract: `comments`/`automation`/`cron`/`search`/…) | +| `ObjectQLCapabilitiesSchema` driver/query booleans | driver-level `DriverCapabilities` / `DatasourceCapabilities` (`@objectstack/spec/data`) — per-connection, resolved at runtime | +| `ObjectStackCapabilitiesSchema` layer roll-up + `ObjectOS*` aliases | none — no replacement import | + +The objectui `@object-ui/types` re-exports of these symbols are dropped in the +companion objectui change. `ClusterCapabilityConfigSchema` / `FeatureFlagSchema` / +`ApiEndpointSchema` (referenced by the dead cluster) are untouched — they live in +their own modules and `ApiEndpointSchema` remains consumed by the stack `apis` key. diff --git a/packages/spec/api-surface.json b/packages/spec/api-surface.json index e908d319c..4581b116f 100644 --- a/packages/spec/api-surface.json +++ b/packages/spec/api-surface.json @@ -47,8 +47,6 @@ "ExpressionSchema (const)", "F (const)", "GUEST_POSITION (const)", - "KernelCapabilities (type)", - "KernelCapabilitiesSchema (const)", "MAP_SUPPORTED_FIELDS (const)", "METADATA_ALIASES (const)", "MIGRATIONS_BY_MAJOR (const)", @@ -67,19 +65,11 @@ "ORGANIZATION_ADMIN (const)", "ORGANIZATION_ADMIN_GRANTS (const)", "ORGANIZATION_ADMIN_NO_BYPASS (const)", - "ObjectOSCapabilities (type)", - "ObjectOSCapabilitiesSchema (const)", - "ObjectQLCapabilities (type)", - "ObjectQLCapabilitiesSchema (const)", "ObjectStack (type)", - "ObjectStackCapabilities (type)", - "ObjectStackCapabilitiesSchema (const)", "ObjectStackDefinition (type)", "ObjectStackDefinitionInput (type)", "ObjectStackDefinitionSchema (const)", "ObjectStackSchema (const)", - "ObjectUICapabilities (type)", - "ObjectUICapabilitiesSchema (const)", "P (const)", "PLATFORM_CAPABILITY_PROVIDERS (const)", "PLATFORM_CAPABILITY_TOKENS (const)", diff --git a/packages/spec/src/index.ts b/packages/spec/src/index.ts index 9795b29cb..ec3cb0129 100644 --- a/packages/spec/src/index.ts +++ b/packages/spec/src/index.ts @@ -59,12 +59,7 @@ export { ComposeStacksOptionsSchema, ConflictStrategySchema, ObjectStackDefinitionSchema, - ObjectStackSchema, - ObjectStackCapabilitiesSchema, - ObjectQLCapabilitiesSchema, - ObjectUICapabilitiesSchema, - KernelCapabilitiesSchema, - ObjectOSCapabilitiesSchema + ObjectStackSchema } from './stack.zod'; export type { DefineStackOptions, ComposeStacksOptions, ConflictStrategy, ObjectStackDefinitionInput } from './stack.zod'; diff --git a/packages/spec/src/stack.test.ts b/packages/spec/src/stack.test.ts index a9bdd0ef5..18303ee1e 100644 --- a/packages/spec/src/stack.test.ts +++ b/packages/spec/src/stack.test.ts @@ -1,402 +1,10 @@ import { describe, it, expect } from 'vitest'; import { - ObjectQLCapabilitiesSchema, - ObjectUICapabilitiesSchema, - KernelCapabilitiesSchema, - ObjectStackCapabilitiesSchema, ObjectStackDefinitionSchema, defineStack, - type ObjectQLCapabilities, - type ObjectUICapabilities, - type KernelCapabilities, - type ObjectStackCapabilities, type ObjectStackDefinitionInput, } from './stack.zod'; -describe('ObjectQLCapabilitiesSchema', () => { - it('should accept valid ObjectQL capabilities with all features enabled', () => { - const capabilities: ObjectQLCapabilities = { - queryFilters: true, - queryAggregations: true, - querySorting: true, - queryPagination: true, - queryWindowFunctions: true, - querySubqueries: true, - queryDistinct: true, - queryHaving: true, - queryJoins: true, - fullTextSearch: true, - vectorSearch: true, - geoSpatial: true, - jsonFields: true, - arrayFields: true, - validationRules: true, - workflows: true, - triggers: true, - formulas: true, - transactions: true, - bulkOperations: true, - supportedDrivers: ['postgresql', 'mongodb', 'mysql'], - }; - - expect(() => ObjectQLCapabilitiesSchema.parse(capabilities)).not.toThrow(); - }); - - it('should accept minimal ObjectQL capabilities', () => { - const capabilities: ObjectQLCapabilities = { - queryFilters: false, - queryAggregations: false, - querySorting: false, - queryPagination: false, - queryWindowFunctions: false, - querySubqueries: false, - queryDistinct: false, - queryHaving: false, - queryJoins: false, - fullTextSearch: false, - vectorSearch: false, - geoSpatial: false, - jsonFields: false, - arrayFields: false, - validationRules: false, - workflows: false, - triggers: false, - formulas: false, - transactions: false, - bulkOperations: false, - }; - - expect(() => ObjectQLCapabilitiesSchema.parse(capabilities)).not.toThrow(); - }); - - it('should use default values for boolean fields', () => { - const result = ObjectQLCapabilitiesSchema.parse({}); - - expect(result.queryFilters).toBe(true); - expect(result.queryAggregations).toBe(true); - expect(result.querySorting).toBe(true); - expect(result.queryPagination).toBe(true); - expect(result.queryWindowFunctions).toBe(false); - expect(result.vectorSearch).toBe(false); - }); - - it('should accept optional supportedDrivers array', () => { - const withDrivers = ObjectQLCapabilitiesSchema.parse({ - supportedDrivers: ['postgresql', 'sqlite', 'excel'], - }); - - expect(withDrivers.supportedDrivers).toEqual(['postgresql', 'sqlite', 'excel']); - - const withoutDrivers = ObjectQLCapabilitiesSchema.parse({}); - expect(withoutDrivers.supportedDrivers).toBeUndefined(); - }); -}); - -describe('ObjectUICapabilitiesSchema', () => { - it('should accept valid ObjectUI capabilities with all features enabled', () => { - const capabilities: ObjectUICapabilities = { - listView: true, - formView: true, - kanbanView: true, - calendarView: true, - ganttView: true, - dashboards: true, - reports: true, - charts: true, - customPages: true, - customThemes: true, - customComponents: true, - customActions: true, - screenFlows: true, - mobileOptimized: true, - accessibility: true, - }; - - expect(() => ObjectUICapabilitiesSchema.parse(capabilities)).not.toThrow(); - }); - - it('should accept minimal ObjectUI capabilities', () => { - const capabilities: ObjectUICapabilities = { - listView: false, - formView: false, - kanbanView: false, - calendarView: false, - ganttView: false, - dashboards: false, - reports: false, - charts: false, - customPages: false, - customThemes: false, - customComponents: false, - customActions: false, - screenFlows: false, - mobileOptimized: false, - accessibility: false, - }; - - expect(() => ObjectUICapabilitiesSchema.parse(capabilities)).not.toThrow(); - }); - - it('should use default values for boolean fields', () => { - const result = ObjectUICapabilitiesSchema.parse({}); - - expect(result.listView).toBe(true); - expect(result.formView).toBe(true); - expect(result.dashboards).toBe(true); - expect(result.kanbanView).toBe(false); - expect(result.customThemes).toBe(false); - }); -}); - -describe('KernelCapabilitiesSchema', () => { - it('keeps the deprecated ObjectOS aliases pointing at the renamed exports', async () => { - const mod = await import('./stack.zod'); - expect(mod.ObjectOSCapabilitiesSchema).toBe(mod.KernelCapabilitiesSchema); - }); - - it('should accept valid kernel capabilities with all features enabled', () => { - const capabilities: KernelCapabilities = { - version: '1.0.0', - environment: 'production', - restApi: true, - odataApi: true, - websockets: true, - serverSentEvents: true, - eventBus: true, - webhooks: true, - apiContracts: true, - authentication: true, - rbac: true, - fieldLevelSecurity: true, - rowLevelSecurity: true, - multiTenant: true, - backgroundJobs: true, - auditLogging: true, - fileStorage: true, - i18n: true, - pluginSystem: true, - features: [], - apis: [], - systemObjects: ['user', 'role', 'permission'], - limits: { - maxObjects: 1000, - maxFieldsPerObject: 500, - maxRecordsPerQuery: 10000, - apiRateLimit: 1000, - fileUploadSizeLimit: 10485760, - }, - }; - - expect(() => KernelCapabilitiesSchema.parse(capabilities)).not.toThrow(); - }); - - it('should require version and environment fields', () => { - expect(() => KernelCapabilitiesSchema.parse({})).toThrow(); - - expect(() => - KernelCapabilitiesSchema.parse({ - version: '1.0.0', - }) - ).toThrow(); - - expect(() => - KernelCapabilitiesSchema.parse({ - version: '1.0.0', - environment: 'development', - }) - ).not.toThrow(); - }); - - it('should validate environment enum values', () => { - expect(() => - KernelCapabilitiesSchema.parse({ - version: '1.0.0', - environment: 'invalid', - }) - ).toThrow(); - - const validEnvironments = ['development', 'test', 'staging', 'production']; - validEnvironments.forEach((env) => { - expect(() => - KernelCapabilitiesSchema.parse({ - version: '1.0.0', - environment: env, - }) - ).not.toThrow(); - }); - }); - - it('should use default values for boolean fields', () => { - const result = KernelCapabilitiesSchema.parse({ - version: '1.0.0', - environment: 'development', - }); - - expect(result.restApi).toBe(true); - expect(result.authentication).toBe(true); - expect(result.fileStorage).toBe(true); - expect(result.multiTenant).toBe(false); - }); - - it('should accept optional limits object', () => { - const withLimits = KernelCapabilitiesSchema.parse({ - version: '1.0.0', - environment: 'production', - limits: { - maxObjects: 500, - apiRateLimit: 100, - }, - }); - - expect(withLimits.limits?.maxObjects).toBe(500); - expect(withLimits.limits?.apiRateLimit).toBe(100); - - const withoutLimits = KernelCapabilitiesSchema.parse({ - version: '1.0.0', - environment: 'development', - }); - - expect(withoutLimits.limits).toBeUndefined(); - }); -}); - -describe('ObjectStackCapabilitiesSchema', () => { - it('should accept complete ObjectStack capabilities with all subsystems', () => { - const capabilities: ObjectStackCapabilities = { - data: { - queryFilters: true, - queryAggregations: true, - querySorting: true, - queryPagination: true, - queryWindowFunctions: true, - querySubqueries: true, - queryDistinct: true, - queryHaving: true, - queryJoins: true, - fullTextSearch: true, - vectorSearch: true, - geoSpatial: true, - jsonFields: true, - arrayFields: true, - validationRules: true, - workflows: true, - triggers: true, - formulas: true, - transactions: true, - bulkOperations: true, - supportedDrivers: ['postgresql', 'mongodb'], - }, - ui: { - listView: true, - formView: true, - kanbanView: true, - calendarView: true, - ganttView: false, - dashboards: true, - reports: true, - charts: true, - customPages: true, - customThemes: false, - customComponents: false, - customActions: true, - screenFlows: true, - mobileOptimized: true, - accessibility: false, - }, - system: { - version: '1.0.0', - environment: 'production', - restApi: true, - odataApi: false, - websockets: true, - serverSentEvents: false, - eventBus: true, - webhooks: true, - apiContracts: false, - authentication: true, - rbac: true, - fieldLevelSecurity: true, - rowLevelSecurity: true, - multiTenant: true, - backgroundJobs: true, - auditLogging: true, - fileStorage: true, - i18n: true, - pluginSystem: false, - systemObjects: ['user', 'role', 'permission', 'object'], - limits: { - maxObjects: 1000, - maxFieldsPerObject: 500, - apiRateLimit: 1000, - }, - }, - }; - - expect(() => ObjectStackCapabilitiesSchema.parse(capabilities)).not.toThrow(); - }); - - it('should require all three subsystem capability objects', () => { - expect(() => ObjectStackCapabilitiesSchema.parse({})).toThrow(); - - expect(() => - ObjectStackCapabilitiesSchema.parse({ - data: {}, - ui: {}, - }) - ).toThrow(); - - expect(() => - ObjectStackCapabilitiesSchema.parse({ - data: {}, - ui: {}, - system: { - version: '1.0.0', - environment: 'development', - }, - }) - ).not.toThrow(); - }); - - it('should allow minimal valid configuration', () => { - const minimal: ObjectStackCapabilities = { - data: {}, - ui: {}, - system: { - version: '0.1.0', - environment: 'development', - }, - }; - - const result = ObjectStackCapabilitiesSchema.parse(minimal); - - // Check that defaults are applied - expect(result.data.queryFilters).toBe(true); - expect(result.ui.listView).toBe(true); - expect(result.system.restApi).toBe(true); - }); - - it('should preserve subsystem-specific optional fields', () => { - const capabilities = ObjectStackCapabilitiesSchema.parse({ - data: { - supportedDrivers: ['postgresql', 'sqlite'], - }, - ui: {}, - system: { - version: '1.0.0', - environment: 'production', - systemObjects: ['user', 'role'], - limits: { - maxObjects: 100, - }, - }, - }); - - expect(capabilities.data.supportedDrivers).toEqual(['postgresql', 'sqlite']); - expect(capabilities.system.systemObjects).toEqual(['user', 'role']); - expect(capabilities.system.limits?.maxObjects).toBe(100); - }); -}); - describe('ObjectStackDefinitionSchema', () => { it('should accept a complete ObjectStack definition', () => { const definition = { diff --git a/packages/spec/src/stack.zod.ts b/packages/spec/src/stack.zod.ts index 0842bd7aa..a99e1230b 100644 --- a/packages/spec/src/stack.zod.ts +++ b/packages/spec/src/stack.zod.ts @@ -5,7 +5,6 @@ import { z } from 'zod'; import { ManifestSchema } from './kernel/manifest.zod'; import { validateObjectNamespacePrefix } from './kernel/namespace-prefix'; import { PLATFORM_CAPABILITY_TOKENS } from './kernel/platform-capabilities'; -import { ClusterCapabilityConfigSchema } from './kernel/cluster.zod'; import { DatasourceSchema } from './data/datasource.zod'; import { TranslationBundleSchema, TranslationConfigSchema } from './system/translation.zod'; import { objectStackErrorMap, formatZodError } from './shared/error-map.zod'; @@ -36,7 +35,6 @@ import { CapabilityDeclarationSchema } from './security/capabilities'; import { SharingRuleSchema } from './security/sharing.zod'; import { ApiEndpointSchema } from './api/endpoint.zod'; -import { FeatureFlagSchema } from './kernel/feature.zod'; // AI Protocol import { AgentSchema } from './ai/agent.zod'; @@ -1314,217 +1312,3 @@ export function composeStacks( return mergeActionsIntoObjects(composed as ObjectStackDefinition); } - - -/** - * 2. RUNTIME CAPABILITIES PROTOCOL (Dynamic) - * ---------------------------------------------------------------------- - * Describes what the ObjectStack platform *is* and *can do*. - * AI Agents read this to understand: - * - What APIs are available? - * - What features are enabled? - * - What limits exist? - * - * The capabilities are organized by subsystem for clarity: - * - ObjectQL: Data Layer capabilities - * - ObjectUI: User Interface Layer capabilities - * - Kernel: System Layer capabilities - */ - -/** - * ObjectQL Capabilities Schema - * - * Defines capabilities related to the Data Layer: - * - Query operations and advanced SQL features - * - Data validation and business logic - * - Database driver support - * - AI/ML data features - */ -export const ObjectQLCapabilitiesSchema = lazySchema(() => z.object({ - /** Query Capabilities */ - queryFilters: z.boolean().default(true).describe('Supports WHERE clause filtering'), - queryAggregations: z.boolean().default(true).describe('Supports GROUP BY and aggregation functions'), - querySorting: z.boolean().default(true).describe('Supports ORDER BY sorting'), - queryPagination: z.boolean().default(true).describe('Supports LIMIT/OFFSET pagination'), - queryWindowFunctions: z.boolean().default(false).describe('Supports window functions with OVER clause'), - querySubqueries: z.boolean().default(false).describe('Supports subqueries'), - queryDistinct: z.boolean().default(true).describe('Supports SELECT DISTINCT'), - queryHaving: z.boolean().default(false).describe('Supports HAVING clause for aggregations'), - queryJoins: z.boolean().default(false).describe('Supports SQL-style joins'), - - /** Advanced Data Features */ - fullTextSearch: z.boolean().default(false).describe('Supports full-text search'), - vectorSearch: z.boolean().default(false).describe('Supports vector embeddings and similarity search for AI/RAG'), - geoSpatial: z.boolean().default(false).describe('Supports geospatial queries and location fields'), - - /** Field Type Support */ - jsonFields: z.boolean().default(true).describe('Supports JSON field types'), - arrayFields: z.boolean().default(false).describe('Supports array field types'), - - /** Data Validation & Logic */ - validationRules: z.boolean().default(true).describe('Supports validation rules'), - workflows: z.boolean().default(true).describe('Supports workflow automation'), - triggers: z.boolean().default(true).describe('Supports database triggers'), - formulas: z.boolean().default(true).describe('Supports formula fields'), - - /** Transaction & Performance */ - transactions: z.boolean().default(true).describe('Supports database transactions'), - bulkOperations: z.boolean().default(true).describe('Supports bulk create/update/delete'), - - /** Driver Support */ - supportedDrivers: z.array(z.string()).optional().describe('Available database drivers (e.g., postgresql, mongodb, excel)'), -})); - -/** - * ObjectUI Capabilities Schema - * - * Defines capabilities related to the UI Layer: - * - View rendering (List, Form, Calendar, etc.) - * - Dashboard and reporting - * - Theming and customization - * - UI actions and interactions - */ -export const ObjectUICapabilitiesSchema = lazySchema(() => z.object({ - /** View Types */ - listView: z.boolean().default(true).describe('Supports list/grid views'), - formView: z.boolean().default(true).describe('Supports form views'), - kanbanView: z.boolean().default(false).describe('Supports kanban board views'), - calendarView: z.boolean().default(false).describe('Supports calendar views'), - ganttView: z.boolean().default(false).describe('Supports Gantt chart views'), - - /** Analytics & Reporting */ - dashboards: z.boolean().default(true).describe('Supports dashboard creation'), - reports: z.boolean().default(true).describe('Supports report generation'), - charts: z.boolean().default(true).describe('Supports chart widgets'), - - /** Customization */ - customPages: z.boolean().default(true).describe('Supports custom page creation'), - customThemes: z.boolean().default(false).describe('Supports custom theme creation'), - customComponents: z.boolean().default(false).describe('Supports custom UI components/widgets'), - - /** Actions & Interactions */ - customActions: z.boolean().default(true).describe('Supports custom button actions'), - screenFlows: z.boolean().default(false).describe('Supports interactive screen flows'), - - /** Responsive & Accessibility */ - mobileOptimized: z.boolean().default(false).describe('UI optimized for mobile devices'), - accessibility: z.boolean().default(false).describe('WCAG accessibility support'), -})); - -/** - * Kernel Capabilities Schema - * - * Defines capabilities related to the System Layer: - * - Runtime environment and platform features - * - API and integration capabilities - * - Security and multi-tenancy - * - System services (events, jobs, audit) - */ -export const KernelCapabilitiesSchema = lazySchema(() => z.object({ - /** System Identity */ - version: z.string().describe('Kernel version'), - environment: z.enum(['development', 'test', 'staging', 'production']), - - /** API Surface */ - restApi: z.boolean().default(true).describe('REST API available'), - odataApi: z.boolean().default(false).describe('OData API available'), - - /** Real-time & Events */ - websockets: z.boolean().default(false).describe('WebSocket support for real-time updates'), - serverSentEvents: z.boolean().default(false).describe('Server-Sent Events support'), - eventBus: z.boolean().default(false).describe('Internal event bus for pub/sub'), - - /** Integration */ - webhooks: z.boolean().default(true).describe('Outbound webhook support'), - apiContracts: z.boolean().default(false).describe('API contract definitions'), - - /** Security & Access Control */ - authentication: z.boolean().default(true).describe('Authentication system'), - rbac: z.boolean().default(true).describe('Role-Based Access Control'), - fieldLevelSecurity: z.boolean().default(false).describe('Field-level permissions'), - rowLevelSecurity: z.boolean().default(false).describe('Row-level security/sharing rules'), - - /** Multi-tenancy */ - multiTenant: z.boolean().default(false).describe('Multi-tenant architecture support'), - - /** Platform Services */ - backgroundJobs: z.boolean().default(false).describe('Background job scheduling'), - auditLogging: z.boolean().default(false).describe('Audit trail logging'), - fileStorage: z.boolean().default(true).describe('File upload and storage'), - - /** Internationalization */ - i18n: z.boolean().default(true).describe('Internationalization support'), - - /** Plugin System */ - pluginSystem: z.boolean().default(false).describe('Plugin/extension system'), - - /** - * Cluster Capability Configuration. - * - * Governs cross-process behaviour: PubSub, Lock, KV, Counter primitives; - * event scope & delivery semantics; service leader election. Optional; - * when absent the kernel uses the in-memory driver (single-process). - * - * @see content/docs/kernel/cluster.mdx - */ - cluster: ClusterCapabilityConfigSchema.optional() - .describe('Cluster transport & semantics configuration.'), - - /** Active Features & Flags */ - features: z.array(FeatureFlagSchema).optional().describe('Active Feature Flags'), - - /** Available APIs */ - apis: z.array(ApiEndpointSchema).optional().describe('Available System & Business APIs'), - network: z.object({ - search: z.boolean().default(false), - websockets: z.boolean().default(false), - files: z.boolean().default(true), - analytics: z.boolean().default(false).describe('Is the Analytics/BI engine enabled?'), - ai: z.boolean().default(false).describe('Is the AI engine enabled?'), - workflow: z.boolean().default(false).describe('Is the Workflow engine enabled?'), - notifications: z.boolean().default(false).describe('Is the Notification service enabled?'), - i18n: z.boolean().default(false).describe('Is the i18n service enabled?'), - }).optional().describe('Network Capabilities (WS, etc.)'), - - /** Introspection */ - systemObjects: z.array(z.string()).optional().describe('List of globally available System Objects'), - - /** Constraints (for AI Generation) */ - limits: z.object({ - maxObjects: z.number().optional(), - maxFieldsPerObject: z.number().optional(), - maxRecordsPerQuery: z.number().optional(), - apiRateLimit: z.number().optional(), - fileUploadSizeLimit: z.number().optional().describe('Max file size in bytes'), - }).optional() -})); - -/** - * Unified ObjectStack Capabilities Schema - * - * Complete capability descriptor for an ObjectStack instance. - * Organized by architectural layer for clarity and maintainability. - */ -export const ObjectStackCapabilitiesSchema = lazySchema(() => z.object({ - /** Data Layer Capabilities (ObjectQL) */ - data: ObjectQLCapabilitiesSchema.describe('Data Layer capabilities'), - - /** User Interface Layer Capabilities (ObjectUI) */ - ui: ObjectUICapabilitiesSchema.describe('UI Layer capabilities'), - - /** System/Runtime Layer Capabilities (Kernel) */ - system: KernelCapabilitiesSchema.describe('System/Runtime Layer capabilities'), -})); - -export type ObjectQLCapabilities = z.infer; -export type ObjectUICapabilities = z.infer; -export type KernelCapabilities = z.infer; -export type ObjectStackCapabilities = z.infer; - -/** @deprecated Renamed — use {@link KernelCapabilitiesSchema}. The "ObjectOS" layer name is retired; ObjectOS now names the commercial runtime environment. */ -export const ObjectOSCapabilitiesSchema = KernelCapabilitiesSchema; -/** @deprecated Renamed — use {@link KernelCapabilities}. */ -export type ObjectOSCapabilities = KernelCapabilities; - - - diff --git a/skills/objectstack-platform/SKILL.md b/skills/objectstack-platform/SKILL.md index dc67e0d38..5fcdc83d0 100644 --- a/skills/objectstack-platform/SKILL.md +++ b/skills/objectstack-platform/SKILL.md @@ -1051,16 +1051,15 @@ const metrics = kernel.getPluginMetrics(); ## Feature Flags Feature flags are a **protocol shape, not a config key**. `FeatureFlagSchema` (from -`@objectstack/spec/kernel`) defines the flag document; in the protocol it appears only on -the runtime capabilities descriptor (`ObjectStackCapabilities.system.features`) that a -platform serves for introspection. There is **no `featureFlags:` / `features:` key on -`defineStack`** — strict parsing silently strips unknown keys, so such config would be a -no-op. +`@objectstack/spec/kernel`) defines the flag document. There is **no `featureFlags:` / +`features:` key on `defineStack`** — strict parsing silently strips unknown keys, so such +config would be a no-op. (The static `ObjectStackCapabilities.system.features` descriptor +that once carried flags was removed with the dead capabilities-descriptor cluster — no +endpoint ever served it; runtime capability discovery is `GET /api/v1/discovery`.) ```typescript import { FeatureFlag } from '@objectstack/spec/kernel'; -import type { ObjectStackCapabilities } from '@objectstack/spec'; // FeatureFlag.create() gives you a compile-checked flag value: const aiCopilot = FeatureFlag.create({ @@ -1072,19 +1071,14 @@ const aiCopilot = FeatureFlag.create({ environment: 'prod', // 'dev' | 'staging' | 'prod' | 'all' (default 'all') }); -// Where flags live in the protocol — the runtime capabilities descriptor: -type SystemFeatures = NonNullable; -const features: SystemFeatures = [ - aiCopilot, - { - name: 'beta_kanban_view', - label: 'Kanban View', - enabled: true, - strategy: 'group', - conditions: { groups: ['beta_testers'] }, - environment: 'all', - }, -]; +const betaKanban = FeatureFlag.create({ + name: 'beta_kanban_view', + label: 'Kanban View', + enabled: true, + strategy: 'group', + conditions: { groups: ['beta_testers'] }, + environment: 'all', +}); ``` Strategies: `boolean` | `percentage` | `user_list` | `group` | `custom`