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
5 changes: 5 additions & 0 deletions .changeset/prune-field-governance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@objectstack/spec": minor
---

chore(spec): prune 7 dead field governance/compliance properties (dead-surface plan, P0/P2). Removes `FieldSchema` props that implied data-protection/governance behavior but had no runtime consumer — false promises (the real at-rest channel is `type: 'secret'`): `encryptionConfig`, `maskingRule`, `auditTrail`, `cached`, `dataQuality`, `writeRequiresMasterRead`, `trackFeedHistory`. Also drops the now-unused `EncryptionConfigSchema`/`MaskingRuleSchema` imports. Kept `caseSensitive` and `dependencies` (potentially functional — conservative). Field types unchanged.
28 changes: 0 additions & 28 deletions packages/spec/liveness/field.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,42 +184,14 @@
"status": "dead",
"evidence": "nested config — renderers read flat multiple/accept/maxSize (FileField.tsx:16); no size/type/virus enforcement in write path"
},
"encryptionConfig": {
"status": "dead",
"evidence": "no consumer; the only at-rest protection is the separate type:'secret' channel (engine.ts encryptSecretFields)"
},
"maskingRule": {
"status": "dead",
"evidence": "no consumer"
},
"auditTrail": {
"status": "dead",
"evidence": "no consumer (aspirational governance)"
},
"dataQuality": {
"status": "dead",
"evidence": "no consumer (aspirational governance)"
},
"cached": {
"status": "dead",
"evidence": "no consumer"
},
"dependencies": {
"status": "dead",
"evidence": "no consumer"
},
"trackFeedHistory": {
"status": "dead",
"evidence": "no consumer"
},
"caseSensitive": {
"status": "dead",
"evidence": "no consumer"
},
"writeRequiresMasterRead": {
"status": "dead",
"evidence": "no consumer (governance)"
},
"inlineTitle": {
"status": "dead",
"evidence": "master-detail explicit override — auto-derivation works (deriveMasterDetail.ts); overrides unread"
Expand Down
7 changes: 0 additions & 7 deletions packages/spec/src/data/field.form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ export const fieldForm = defineForm({
fields: [
{ field: 'expression', widget: 'textarea', helpText: 'CEL expression to calculate this field (makes it read-only)' },
{ field: 'summaryOperations', type: 'composite', helpText: 'Roll-up summary configuration (for parent-child relationships)' },
{ field: 'cached', type: 'composite', helpText: 'Caching configuration for computed fields' },
],
},
{
Expand All @@ -78,12 +77,6 @@ export const fieldForm = defineForm({
{ field: 'hidden', colSpan: 1, helpText: 'Hide field from default UI views' },
{ field: 'searchable', colSpan: 1, helpText: 'Include in global search results' },
{ field: 'sortable', colSpan: 1, helpText: 'Allow sorting lists by this field' },
// Audit & History
{ field: 'auditTrail', colSpan: 1, helpText: 'Track detailed changes with user and timestamp' },
{ field: 'trackFeedHistory', colSpan: 1, helpText: 'Show changes in activity feed' },
// Security & Compliance
{ field: 'encryptionConfig', type: 'composite', colSpan: 2, helpText: 'Field-level encryption (GDPR/HIPAA/PCI-DSS)' },
{ field: 'maskingRule', type: 'composite', colSpan: 2, helpText: 'Data masking rules for PII protection' },
],
},
],
Expand Down
1 change: 0 additions & 1 deletion packages/spec/src/data/field.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,6 @@ describe('FieldSchema', () => {
type: 'master_detail',
reference: 'parent_object',
deleteBehavior: 'cascade',
writeRequiresMasterRead: true,
};

const result = FieldSchema.parse(masterDetailField);
Expand Down
29 changes: 6 additions & 23 deletions packages/spec/src/data/field.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import { z } from 'zod';
import { SystemIdentifierSchema } from '../shared/identifiers.zod';
import { ExpressionInputSchema } from '../shared/expression.zod';
import { EncryptionConfigSchema } from '../system/encryption.zod';
import { MaskingRuleSchema } from '../system/masking.zod';

/**
* Field Type Enum
Expand Down Expand Up @@ -401,7 +399,6 @@ export const FieldSchema = lazySchema(() => z.object({
+ 'Required for relationship types. Used by $expand to resolve foreign key IDs into full objects.'
),
referenceFilters: z.array(z.string()).optional().describe('Filters applied to lookup dialogs (e.g. "active = true")'),
writeRequiresMasterRead: z.boolean().optional().describe('If true, user needs read access to master record to edit this field'),
deleteBehavior: z.enum(['set_null', 'cascade', 'restrict']).optional().default('set_null').describe('What happens if referenced record is deleted'),
/**
* Master-detail INLINE EDITING. On a child's `master_detail`/`lookup` field
Expand Down Expand Up @@ -477,27 +474,14 @@ export const FieldSchema = lazySchema(() => z.object({
// File attachment field config
fileAttachmentConfig: FileAttachmentConfigSchema.optional().describe('Configuration for file and attachment field types'),

/** Enhanced Security & Compliance */
// Encryption configuration
encryptionConfig: EncryptionConfigSchema.optional().describe('Field-level encryption configuration for sensitive data (GDPR/HIPAA/PCI-DSS)'),

// Data masking rules
maskingRule: MaskingRuleSchema.optional().describe('Data masking rules for PII protection'),

// Audit trail
auditTrail: z.boolean().default(false).describe('Enable detailed audit trail for this field (tracks all changes with user and timestamp)'),

// Pruned 2026-06 (dead in both layers — aspirational governance with no runtime
// consumer; encryption/masking implied at-rest protection that never happened —
// the real channel is type:'secret'). See
// docs/audits/2026-06-dead-surface-disposition-plan.md (P0/P2 field prune):
// encryptionConfig, maskingRule, auditTrail, cached, dataQuality.

/** Field Dependencies & Relationships */
// Field dependencies
dependencies: z.array(z.string()).optional().describe('Array of field names that this field depends on (for formulas, visibility rules, etc.)'),

/** Computed Field Optimization */
// Computed field caching
cached: ComputedFieldCacheSchema.optional().describe('Caching configuration for computed/formula fields'),

/** Data Quality & Governance */
// Data quality rules
dataQuality: DataQualityRulesSchema.optional().describe('Data quality validation and monitoring rules'),

/** Layout & Grouping */
group: z.string().optional().describe('Field group name for organizing fields in forms and layouts (e.g., "contact_info", "billing", "system")'),
Expand All @@ -523,7 +507,6 @@ export const FieldSchema = lazySchema(() => z.object({
system: z.boolean().optional().describe('Auto-injected system/audit field (e.g. created_at, updated_by, organization_id). Tools that surface system fields separately from author-declared business fields should branch on this flag.'),
sortable: z.boolean().optional().default(true).describe('Whether field is sortable in list views'),
inlineHelpText: z.string().optional().describe('Help text displayed below the field in forms'),
trackFeedHistory: z.boolean().optional().describe('Track field changes in Chatter/activity feed (Salesforce pattern)'),
caseSensitive: z.boolean().optional().describe('Whether text comparisons are case-sensitive'),
autonumberFormat: z.string().optional().describe('Auto-number display format pattern (e.g., "CASE-{0000}")'),
/** Indexing */
Expand Down
Loading