From 2dce1a11419eef4c94ea3aedd7fab34da6dda4c9 Mon Sep 17 00:00:00 2001 From: os-zhuang Date: Tue, 16 Jun 2026 14:32:50 +0800 Subject: [PATCH] chore(spec): prune 7 dead field governance/compliance props (dead-surface plan) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes FieldSchema props that implied data-protection/governance behavior but had zero runtime consumer — false promises (encryption/masking imply at-rest protection that never happened; the real channel is type:'secret'): encryptionConfig · maskingRule · auditTrail · cached · dataQuality · writeRequiresMasterRead · trackFeedHistory Cleanup: field.zod.ts schema + the now-unused EncryptionConfigSchema/MaskingRuleSchema imports + field.form.ts (5 form fields) + field.test.ts (writeRequiresMasterRead) + field.json ledger; reference docs regenerated. Kept caseSensitive + dependencies (potentially functional — conservative). Field *types* unchanged. Verified: liveness gate green (field 34 live/17 dead); full @objectstack/spec suite green (242 files, 6562 tests); grep-confirmed no object def/seed constructs them; ran the real `objectstack dev` showcase (37 plugins, 75 objects) — boots clean, Console 200, showcase_field_zoo parses+serves (code field no longer carries auditTrail), no field errors in the server log. Second batch of the dead-surface disposition plan (per-cluster verified PRs). Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/prune-field-governance.md | 5 +++++ packages/spec/liveness/field.json | 28 --------------------------- packages/spec/src/data/field.form.ts | 7 ------- packages/spec/src/data/field.test.ts | 1 - packages/spec/src/data/field.zod.ts | 29 ++++++---------------------- 5 files changed, 11 insertions(+), 59 deletions(-) create mode 100644 .changeset/prune-field-governance.md diff --git a/.changeset/prune-field-governance.md b/.changeset/prune-field-governance.md new file mode 100644 index 0000000000..72a0529296 --- /dev/null +++ b/.changeset/prune-field-governance.md @@ -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. diff --git a/packages/spec/liveness/field.json b/packages/spec/liveness/field.json index 6ab7fbcf95..630a92f2b1 100644 --- a/packages/spec/liveness/field.json +++ b/packages/spec/liveness/field.json @@ -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" diff --git a/packages/spec/src/data/field.form.ts b/packages/spec/src/data/field.form.ts index 7c83b428a5..9be4ff6ba5 100644 --- a/packages/spec/src/data/field.form.ts +++ b/packages/spec/src/data/field.form.ts @@ -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' }, ], }, { @@ -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' }, ], }, ], diff --git a/packages/spec/src/data/field.test.ts b/packages/spec/src/data/field.test.ts index 94c31deb90..1d3400cb50 100644 --- a/packages/spec/src/data/field.test.ts +++ b/packages/spec/src/data/field.test.ts @@ -279,7 +279,6 @@ describe('FieldSchema', () => { type: 'master_detail', reference: 'parent_object', deleteBehavior: 'cascade', - writeRequiresMasterRead: true, }; const result = FieldSchema.parse(masterDetailField); diff --git a/packages/spec/src/data/field.zod.ts b/packages/spec/src/data/field.zod.ts index 2aa746308e..5ccde515f2 100644 --- a/packages/spec/src/data/field.zod.ts +++ b/packages/spec/src/data/field.zod.ts @@ -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 @@ -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 @@ -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")'), @@ -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 */