From 83db8e1db6aaba76e93469ee1540f38d6159b994 Mon Sep 17 00:00:00 2001 From: os-zhuang Date: Tue, 16 Jun 2026 13:47:48 +0800 Subject: [PATCH] =?UTF-8?q?docs(audits):=20dead-surface=20disposition=20pl?= =?UTF-8?q?an=20(spec=20liveness=20=E2=86=92=20executable=20decision)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec-liveness gate now quantifies 89 dead properties across 10 governed metadata types, but the gate only measures — it doesn't decide what to do. This turns that measurement into an executable plan: for each dead property, recommend prune / wire-rename / enforce-or-prune / objectui with rationale, cost and risk, priority-ordered (P0 false-compliance → P1 naming-drift bugs → P2 aspirational-surface prune). Headline: ~64 of 89 are PRUNE candidates — aspirational enterprise config, duplicate flags, and display options with no roadmap. For a platform selling a trustworthy metadata contract, shedding false surface is the highest-leverage hygiene move (narrow-and-true). The team owns execution (spec removals, enforcement); this is the decision input. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/dead-surface-plan.md | 4 + .../2026-06-dead-surface-disposition-plan.md | 86 +++++++++++++++++++ docs/audits/README.md | 3 + 3 files changed, 93 insertions(+) create mode 100644 .changeset/dead-surface-plan.md create mode 100644 docs/audits/2026-06-dead-surface-disposition-plan.md diff --git a/.changeset/dead-surface-plan.md b/.changeset/dead-surface-plan.md new file mode 100644 index 0000000000..8571d41ad9 --- /dev/null +++ b/.changeset/dead-surface-plan.md @@ -0,0 +1,4 @@ +--- +--- + +docs(audits): add the dead-surface disposition plan — turns the spec-liveness gate's 89 `dead` properties (10 governed types) into an executable prune / wire-rename / enforce-or-prune decision, priority-ordered. Decision artifact; no package impact. diff --git a/docs/audits/2026-06-dead-surface-disposition-plan.md b/docs/audits/2026-06-dead-surface-disposition-plan.md new file mode 100644 index 0000000000..d73a90c831 --- /dev/null +++ b/docs/audits/2026-06-dead-surface-disposition-plan.md @@ -0,0 +1,86 @@ +# Dead-surface disposition plan (spec liveness) + +**Date**: 2026-06-16 · **Input**: the spec-liveness gate (`packages/spec/liveness/`) over 10 governed metadata types. **Builds on**: [ADR-0049](../adr/0049-no-unenforced-security-properties.md) (security enforce-or-remove). **Purpose**: turn the gate's measurement into an executable decision — for each of the **89 `dead` properties**, recommend **enforce / wire-rename / prune / mark-experimental / defer / objectui** with rationale, cost and risk. + +> The gate already proves these properties have no framework runtime consumer. This document decides what to *do* about each. It makes recommendations; the team owns execution (especially spec removals and runtime enforcement). + +## Headline + +**The dominant disposition is PRUNE (~64 of 89).** Most dead surface is aspirational enterprise config, duplicate flags, or display options that nobody reads and nobody has a committed roadmap for. For a platform whose value proposition is a *trustworthy* metadata contract (and whose positioning is an open Ontology protocol), **shedding false surface is the highest-leverage hygiene move** — under-promise in the spec, deliver what's declared. "Narrow and true" beats "broad and half-wired." + +| Disposition | Count | Meaning | +|---|---|---| +| **PRUNE** | ~64 | Remove from spec. No roadmap; aspirational / duplicate / display-only. Shrinks false surface. | +| **WIRE-RENAME** | ~8 | A user-visible *bug*: the property is meant to work but reads under a wrong key, or duplicates a flat sibling. Fix the key / route the consumer. | +| **ENFORCE-or-PRUNE** | ~6 | Security/scoping-relevant — needs a product call: build the enforcement, or remove the false promise. Do **not** leave as silent dead. | +| **OBJECTUI** | 1 | Fix lives in the separate `objectui` renderer repo (can't be done here). | + +Security note carried over from ADR-0049: a *dead security/governance property is worse than absent* — it implies a boundary that isn't there. The P0 cluster below is exactly those. + +--- + +## Priority-ordered actions + +### P0 — false-compliance / security-relevant dead → decide enforce-or-remove (don't leave) +These imply a security/governance/isolation boundary that does not exist. + +| Property | Disposition | Why · cost · risk | +|---|---|---| +| `field.encryptionConfig` | **PRUNE** | Implies at-rest encryption; the only real channel is `type:'secret'` (engine `encryptSecretFields`). A field-level encryptionConfig is false assurance. Remove + point authors to `secret`. Low cost; risk: seeds using it. | +| `field.maskingRule` | **PRUNE** | Implies field masking; no consumer. False data-protection promise. Remove. | +| `field.writeRequiresMasterRead` | **PRUNE** | Governance flag, no consumer. Remove. | +| `field.dataQuality` / `field.auditTrail` | **PRUNE** | Aspirational governance, no runtime. Remove (re-introduce with the feature). | +| `permission.contextVariables` | **PRUNE** | Doc claims runtime RLS evaluation; RLS uses only `current_user.*` built-ins. Misleading — remove. | +| `permission.isProfile` | **PRUNE** | profile-vs-permset never gates anything. Remove (the `profile` type alias already conveys intent). | +| `agent.tenantId` | **ENFORCE-or-PRUNE** | Multi-tenant agent isolation — if agents must be tenant-scoped, wire it in the runtime; else remove. Product call. | +| `skill.permissions` | **ENFORCE-or-PRUNE** | A skill should be restrictable; today unenforced + naming drift (`requiredPermissions`). Enforce at skill-activation, or remove + drop the drift. | + +### P1 — naming-drift / duplication *bugs* (authors set them, they silently no-op) → wire or rename +User-visible: documented per the protocol, fails silently. + +| Property | Disposition | Why · cost · risk | +|---|---|---| +| `field.referenceFilters` | **WIRE-RENAME** | Lookup dialog reads `lookup_filters`; normalize the key so the documented camelCase works. Net user-facing fix. (renderer side = objectui) | +| `field.columnName` | **WIRE-RENAME → else PRUNE** | DANGEROUS: advertises custom physical column names the driver never honors (`resolveColumnName` has 0 call sites). Either wire it in driver-sql or remove. Removal is safer. | +| `field.currencyConfig` / `field.vectorConfig` / `field.fileAttachmentConfig` | **PRUNE (pick flat)** | Nested config is dead; renderers read flat siblings (`currency`/`precision`, `dimensions`, `multiple`/`accept`/`maxSize`). Remove the nested form — one shape per field type. | +| `agent.knowledge` | **WIRE-RENAME → else PRUNE** | Shape drift `{topics,indexes}` vs read `{sources}`; no runtime reader (RAG via `service-knowledge`). Reconcile the shape or remove (RAG is wired elsewhere). | +| `action.disabled` | **OBJECTUI** | CEL form ignored; primary renderers read non-spec `enabled` and invert. Fix is in the objectui renderers (`action-button.tsx`) + normalize the key. Cross-repo. | + +### P2 — aspirational / duplicate / display surface → PRUNE (narrow-and-true) +No security implication; no roadmap; removing shrinks false surface. Grouped for batch removal. + +**object (≈22)** — the largest prune target: +`enable.{trackHistory,searchable,files,feeds,activities,trash,mru,clone}` (capability flags, no readers — `apiEnabled`/`apiMethods` already enforced, #1937); `versioning` / `partitioning` / `cdc` (aspirational enterprise blocks); `softDelete` & `search` (duplicate the dead `enable.trash`/`enable.searchable`); `recordTypes` / `defaultDetailForm` (unimplemented, elaborate docstrings); `recordName` (superseded by field `autonumber`); `keyPrefix` / `tags` / `abstract` / `isSystem` / `active` (no reader); `tenancy.{strategy,tenantField,crossTenantAccess}` (only `tenancy.enabled` is live). + +**field (≈24)** — enhanced-type display config + redundant flags: +`theme` / `lineNumbers` (code: only `language` live); `allowHalf` / `maxRating` (rating: `max` live); `displayMap` / `allowGeocoding` / `addressFormat`; `colorFormat` / `allowAlpha` / `presetColors`; `showValue` / `marks` (slider: min/max/step live); `barcodeFormat` / `qrErrorCorrection` / `displayValue` / `allowScanning`; `inlineTitle` / `inlineColumns` / `inlineAmountField` / `relatedList` / `relatedListTitle` / `relatedListColumns` (master-detail explicit overrides — auto-derivation works); `searchable` / `index` / `externalId` (field-level — superseded by object/dataset-level); `cached` / `dependencies` / `trackFeedHistory` / `caseSensitive`. + +**flow (5)**: `description` / `template` (no reader); `active` (deprecated, redundant with `status`); `nodes.outputSchema` (never validated); `nodes.boundaryConfig` (drives the dead BPMN `boundary_event`); `errorHandling.fallbackNodeId` (engine uses per-node fault edges). *Special:* `flow.status` — currently doesn't gate (engine uses an in-memory `flowEnabled` map); **WIRE** `status` → the enable map, or accept it's display-only and prune. Product call. + +**tool (5)**: `category` / `requiresConfirmation` / `permissions` / `active` / `builtIn` — cosmetic on a write-only projection. Prune. *(The deeper question — make `tool` metadata authoritative vs stop projecting a schema that implies authorability — is a design decision, not a prune; track separately.)* + +**action (3)**: `execute` (deprecated, auto-migrated to `target`); `shortcut` (registered but no keydown listener); `bulkEnabled` (no spec-driven path calls `executeBulk`); `timeout` (server uses `body.timeoutMs`). Prune (or wire shortcut/bulk if wanted). + +**hook (1)**: `label` **or** `description` — keep one for docs, drop the redundant other. + +**role (1)**: `parent` — manager rollup unimplemented (org hierarchy uses `sys_department`). **PRUNE** now; re-introduce with the hierarchy feature, or **DEFER-M2** if roadmapped. + +**skill (1)**: `triggerPhrases` — no intent matcher exists. **PRUNE** (remove the misleading "activates this skill" framing) or **ENFORCE** if intent-routing is on the roadmap. + +--- + +## Execution guidance + +- **Pruning is low-risk and mechanical**: each is a spec property removal + ledger entry removal; CI (`validate`/seed fixtures + the liveness gate) catches anything that authored the removed prop. Batch by type into a few PRs (one per type keeps review tight). Estimated: object + field prunes are ~2 PRs covering ~46 of the 64. +- **Wire-rename** items are bug-fixes; the renderer-side ones (`referenceFilters`, `action.disabled`) land in **objectui**. +- **ENFORCE-or-PRUNE (P0)** items need a one-line product decision each; default to **prune** (remove the false promise) unless there's a committed roadmap, per ADR-0049. +- After each prune/enforce, the liveness ledger updates and the gate stays green — the loop closes. + +## Sequencing recommendation + +1. **P0 first** (8 props) — false-compliance is the trust risk; mostly prunes, fast. +2. **P2 object + field prune** (~46 props) — biggest surface reduction, low risk, high signal ("the spec got honest"). +3. **P1 wire-rename** — schedule the framework-side ones; file the objectui ones in that repo. +4. **Remaining P2** (flow/tool/action/hook/role/skill) — opportunistic. + +The security cluster already handled by ADR-0049 (Policy tree, `allow{Transfer,Restore,Purge}`, SharingRule, flow `runAs`) is **not** re-listed here — those are `experimental`/M2, not `dead`. diff --git a/docs/audits/README.md b/docs/audits/README.md index 0fdb329ea9..0bb8192d9b 100644 --- a/docs/audits/README.md +++ b/docs/audits/README.md @@ -59,6 +59,9 @@ dataset `filter`/`format`/`derived`/`dateGranularity`; skill `triggerConditions` - **Healthiest** (near-total liveness, model schemas): **hook**, **validation**. - **Worst**: **policy** (100% dead), **portal** (100% dead), **tool** (write-only). +## Disposition plan +- [`2026-06-dead-surface-disposition-plan.md`](./2026-06-dead-surface-disposition-plan.md) — turns the spec-liveness gate's 89 `dead` properties (10 governed types) into an executable decision: **prune / wire-rename / enforce-or-prune / objectui**, priority-ordered. Headline: ~64 are prune candidates (aspirational/duplicate/display with no roadmap). + ## Suggested ADRs 1. **Security enforcement** (cluster #1) — highest priority; either enforce or remove every parsed-but-unenforced security prop. 2. **Finish ADR-0021** (cluster #2) — migrate chart/dashboard/report renderers + Studio off the legacy inline shape.