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
55 changes: 55 additions & 0 deletions .changeset/remove-dead-metadata-props-2377.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
"@objectstack/spec": minor
---

feat(spec)!: remove dead author-facing metadata properties (#2377, ADR-0049 enforce-or-remove)

Breaking spec-surface removal, versioned as `minor` per the launch-window changeset
policy (a `major` would promote the whole fixed-group monorepo; breaking cleanups ride
the minor line, as with #2402 → 11.1.0).

Removes a batch of spec properties that parsed but had **no runtime consumer** —
authoring them was a false affordance (especially dangerous for AI-authored
metadata). Verified dead against the liveness ledger (`packages/spec/liveness/*.json`)
and a repo-wide grep of readers. This is the follow-up slice to #2402.

## Removed (each was `dead` + no reader anywhere)

- **field** (`field.zod.ts`): `vectorConfig` (+ `VectorConfigSchema` + types),
`fileAttachmentConfig` (+ `FileAttachmentConfigSchema` + types), `dependencies`.
Vector fields keep the live flat `dimensions` prop; file/image fields keep the
live flat `multiple`/`accept`/`maxSize` siblings.
- **object** (`object.zod.ts`): `versioning` (+ `VersioningConfigSchema`),
`softDelete` (+ `SoftDeleteConfigSchema`), `search` (+ `SearchConfigSchema`),
`recordName`, `keyPrefix`. Each is now a **rejecting tombstone** in
`UNKNOWN_KEY_GUIDANCE` carrying the upgrade prescription.
- **action** (`action.zod.ts`): `timeout` (server uses `body.timeoutMs`; no
action-level timeout is enforced).
- **agent** (`agent.zod.ts`): `planning.strategy`, `planning.allowReplan`
(only `planning.maxIterations` is read by the runtime).
- **dataset** (`dataset.zod.ts`): `measures.certified` (declared-but-unenforced
governance flag — never compiled into the Cube).

Liveness ledgers, the ledger README table, and `api-surface.json` are updated;
the removed sub-schema keys are dropped from `json-schema.manifest.json`.

## Migration

- **field/agent/dataset/action props**: authoring them is now silently stripped
(they never did anything). Remove them. Vector → set flat `dimensions`;
file/image → set flat `multiple`/`accept`/`maxSize`.
- **object props**: `ObjectSchema.create()` now throws a located error naming the
replacement — `versioning`/`softDelete` → hard deletes + `Field.trackHistory` /
`lifecycle`; `search` → `searchableFields`; `recordName` → an `autonumber`
`Field` designated as `nameField`; `keyPrefix` → remove (never had an effect).

## Deliberately NOT removed (dead, but entangled — a scoped follow-up)

`field.index`/`columnName`/`referenceFilters` and object
`tags`/`active`/`isSystem`/`abstract`/`enable.searchable`/`enable.trash`/`enable.mru`
and `agent.tenantId` are surfaced in the Studio metadata-authoring forms
(`*.form.ts`) — removing them cascades into i18n bundle regeneration, so they are
deferred. `action.type:'form'` has a dedicated build-time lint (`lint-view-refs.ts`)
and a first-party showcase usage, so it needs a UX decision. `field.columnName`
additionally has an ADR-0062 D7 lint. These stay `dead` + `authorWarn` in the
ledgers.
2 changes: 1 addition & 1 deletion content/docs/references/ai/agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const result = AIKnowledge.parse(data);
| **permissions** | `string[]` | optional | Required permission-set capabilities |
| **tenantId** | `string` | optional | Tenant/Organization ID |
| **visibility** | `Enum<'global' \| 'organization' \| 'private'>` | ✅ | [EXPERIMENTAL — NOT ENFORCED, #1901] Intended listing scope. No runtime consumer yet; use access/permissions for real gating. |
| **planning** | `{ strategy: Enum<'react' \| 'plan_and_execute' \| 'reflexion' \| 'tree_of_thought'>; maxIterations: integer; allowReplan: boolean }` | optional | Autonomous reasoning and planning configuration |
| **planning** | `{ maxIterations: integer }` | optional | Autonomous reasoning and planning configuration |
| **memory** | `{ longTerm?: object; reflectionInterval?: integer }` | optional | Agent memory management |
| **guardrails** | `{ maxTokensPerInvocation?: integer; maxExecutionTimeSec?: integer; blockedTopics?: string[] }` | optional | Safety guardrails for the agent |
| **structuredOutput** | `{ format: Enum<'json_object' \| 'json_schema' \| 'regex' \| 'grammar' \| 'xml'>; schema?: Record<string, any>; strict: boolean; retryOnValidationFailure: boolean; … }` | optional | Structured output format and validation configuration |
Expand Down
1 change: 0 additions & 1 deletion content/docs/references/api/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"metadata",
"metadata-plugin",
"notification",
"object",
"odata",
"package-api",
"package-registry",
Expand Down
42 changes: 0 additions & 42 deletions content/docs/references/api/object.mdx

This file was deleted.

23 changes: 21 additions & 2 deletions content/docs/references/api/versioning.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ Architecture Alignment:
## TypeScript Usage

```typescript
import { VersionDefinition, VersionNegotiationResponse, VersionStatus, VersioningStrategy } from '@objectstack/spec/api';
import type { VersionDefinition, VersionNegotiationResponse, VersionStatus, VersioningStrategy } from '@objectstack/spec/api';
import { VersionDefinition, VersionNegotiationResponse, VersionStatus, VersioningConfig, VersioningStrategy } from '@objectstack/spec/api';
import type { VersionDefinition, VersionNegotiationResponse, VersionStatus, VersioningConfig, VersioningStrategy } from '@objectstack/spec/api';

// Validate data
const result = VersionDefinition.parse(data);
Expand Down Expand Up @@ -84,6 +84,25 @@ const result = VersionDefinition.parse(data);
* `retired`


---

## VersioningConfig

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **strategy** | `Enum<'urlPath' \| 'header' \| 'queryParam' \| 'dateBased'>` | ✅ | How the API version is specified by clients |
| **current** | `string` | ✅ | The current/recommended API version identifier |
| **default** | `string` | ✅ | Fallback version when client does not specify one |
| **versions** | `{ version: string; status: Enum<'preview' \| 'current' \| 'supported' \| 'deprecated' \| 'retired'>; releasedAt: string; deprecatedAt?: string; … }[]` | ✅ | All available API versions with lifecycle metadata |
| **headerName** | `string` | ✅ | HTTP header name for version negotiation (header/dateBased strategies) |
| **queryParamName** | `string` | ✅ | Query parameter name for version specification (queryParam strategy) |
| **urlPrefix** | `string` | ✅ | URL prefix before version segment (urlPath strategy) |
| **deprecation** | `{ warnHeader: boolean; sunsetHeader: boolean; linkHeader: boolean; rejectRetired: boolean; … }` | optional | Deprecation lifecycle behavior |
| **includeInDiscovery** | `boolean` | ✅ | Include version information in the API discovery endpoint |


---

## VersioningStrategy
Expand Down
56 changes: 2 additions & 54 deletions content/docs/references/data/field.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ Field Type Enum
## TypeScript Usage

```typescript
import { Address, ComputedFieldCache, CurrencyConfig, CurrencyValue, DataQualityRules, Field, FieldType, FileAttachmentConfig, LocationCoordinates, SelectOption, VectorConfig } from '@objectstack/spec/data';
import type { Address, ComputedFieldCache, CurrencyConfig, CurrencyValue, DataQualityRules, Field, FieldType, FileAttachmentConfig, LocationCoordinates, SelectOption, VectorConfig } from '@objectstack/spec/data';
import { Address, ComputedFieldCache, CurrencyConfig, CurrencyValue, DataQualityRules, Field, FieldType, LocationCoordinates, SelectOption } from '@objectstack/spec/data';
import type { Address, ComputedFieldCache, CurrencyConfig, CurrencyValue, DataQualityRules, Field, FieldType, LocationCoordinates, SelectOption } from '@objectstack/spec/data';

// Validate data
const result = Address.parse(data);
Expand Down Expand Up @@ -139,10 +139,7 @@ const result = Address.parse(data);
| **step** | `number` | optional | Step increment for slider (default: 1) |
| **currencyConfig** | `{ precision?: integer; currencyMode?: Enum<'dynamic' \| 'fixed'>; defaultCurrency?: string }` | optional | Configuration for currency field type |
| **dimensions** | `integer` | optional | Vector dimensionality (e.g., 1536 for OpenAI embeddings) |
| **vectorConfig** | `{ dimensions: integer; distanceMetric?: Enum<'cosine' \| 'euclidean' \| 'dotProduct' \| 'manhattan'>; normalized?: boolean; indexed?: boolean; … }` | optional | Configuration for vector field type (AI/ML embeddings) |
| **fileAttachmentConfig** | `{ minSize?: number; maxSize?: number; allowedTypes?: string[]; blockedTypes?: string[]; … }` | optional | Configuration for file and attachment field types |
| **trackHistory** | `boolean` | optional | Render this field's value changes as human-readable entries on the record activity timeline (ADR-0052 §5b). Opt-in per field. |
| **dependencies** | `string[]` | optional | Array of field names that this field depends on (for formulas, visibility rules, etc.) |
| **group** | `string` | optional | Field group name for organizing fields in forms and layouts (e.g., "contact_info", "billing", "system") |
| **visibleWhen** | `string \| { dialect: Enum<'cel' \| 'js' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | Predicate (CEL) — field is shown only when TRUE (else hidden). e.g. P`record.type == 'invoice'` |
| **readonlyWhen** | `string \| { dialect: Enum<'cel' \| 'js' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | Predicate (CEL) — field is read-only when TRUE. e.g. P`record.status == 'paid'` |
Expand Down Expand Up @@ -217,40 +214,6 @@ const result = Address.parse(data);
* `vector`


---

## FileAttachmentConfig

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **minSize** | `number` | optional | Minimum file size in bytes |
| **maxSize** | `number` | optional | Maximum file size in bytes (e.g., 10485760 = 10MB) |
| **allowedTypes** | `string[]` | optional | Allowed file extensions (e.g., [".pdf", ".docx", ".jpg"]) |
| **blockedTypes** | `string[]` | optional | Blocked file extensions (e.g., [".exe", ".bat", ".sh"]) |
| **allowedMimeTypes** | `string[]` | optional | Allowed MIME types (e.g., ["image/jpeg", "application/pdf"]) |
| **blockedMimeTypes** | `string[]` | optional | Blocked MIME types |
| **virusScan** | `boolean` | ✅ | Enable virus scanning for uploaded files |
| **virusScanProvider** | `Enum<'clamav' \| 'virustotal' \| 'metadefender' \| 'custom'>` | optional | Virus scanning service provider |
| **virusScanOnUpload** | `boolean` | ✅ | Scan files immediately on upload |
| **quarantineOnThreat** | `boolean` | ✅ | Quarantine files if threat detected |
| **storageProvider** | `string` | optional | Object storage provider name (references ObjectStorageConfig) |
| **storageBucket** | `string` | optional | Target bucket name |
| **storagePrefix** | `string` | optional | Storage path prefix (e.g., "uploads/documents/") |
| **imageValidation** | `{ minWidth?: number; maxWidth?: number; minHeight?: number; maxHeight?: number; … }` | optional | Image-specific validation rules |
| **allowMultiple** | `boolean` | ✅ | Allow multiple file uploads (overrides field.multiple) |
| **allowReplace** | `boolean` | ✅ | Allow replacing existing files |
| **allowDelete** | `boolean` | ✅ | Allow deleting uploaded files |
| **requireUpload** | `boolean` | ✅ | Require at least one file when field is required |
| **extractMetadata** | `boolean` | ✅ | Extract file metadata (name, size, type, etc.) |
| **extractText** | `boolean` | ✅ | Extract text content from documents (OCR/parsing) |
| **versioningEnabled** | `boolean` | ✅ | Keep previous versions of replaced files |
| **maxVersions** | `number` | optional | Maximum number of versions to retain |
| **publicRead** | `boolean` | ✅ | Allow public read access to uploaded files |
| **presignedUrlExpiry** | `number` | ✅ | Presigned URL expiration in seconds (default: 1 hour) |


---

## LocationCoordinates
Expand Down Expand Up @@ -282,18 +245,3 @@ const result = Address.parse(data);

---

## VectorConfig

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **dimensions** | `integer` | ✅ | Vector dimensionality (e.g., 1536 for OpenAI embeddings) |
| **distanceMetric** | `Enum<'cosine' \| 'euclidean' \| 'dotProduct' \| 'manhattan'>` | ✅ | Distance/similarity metric for vector search |
| **normalized** | `boolean` | ✅ | Whether vectors are normalized (unit length) |
| **indexed** | `boolean` | ✅ | Whether to create a vector index for fast similarity search |
| **indexType** | `Enum<'hnsw' \| 'ivfflat' \| 'flat'>` | optional | Vector index algorithm (HNSW for high accuracy, IVFFlat for large datasets) |


---

1 change: 0 additions & 1 deletion content/docs/references/data/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"notification",
"object",
"query",
"search-engine",
"seed",
"seed-loader",
"subscription",
Expand Down
Loading