Skip to content

Commit 83db8e1

Browse files
os-zhuangclaude
andcommitted
docs(audits): dead-surface disposition plan (spec liveness → executable decision)
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) <noreply@anthropic.com>
1 parent 7fe0b91 commit 83db8e1

3 files changed

Lines changed: 93 additions & 0 deletions

File tree

.changeset/dead-surface-plan.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
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.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Dead-surface disposition plan (spec liveness)
2+
3+
**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.
4+
5+
> 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).
6+
7+
## Headline
8+
9+
**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."
10+
11+
| Disposition | Count | Meaning |
12+
|---|---|---|
13+
| **PRUNE** | ~64 | Remove from spec. No roadmap; aspirational / duplicate / display-only. Shrinks false surface. |
14+
| **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. |
15+
| **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. |
16+
| **OBJECTUI** | 1 | Fix lives in the separate `objectui` renderer repo (can't be done here). |
17+
18+
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.
19+
20+
---
21+
22+
## Priority-ordered actions
23+
24+
### P0 — false-compliance / security-relevant dead → decide enforce-or-remove (don't leave)
25+
These imply a security/governance/isolation boundary that does not exist.
26+
27+
| Property | Disposition | Why · cost · risk |
28+
|---|---|---|
29+
| `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. |
30+
| `field.maskingRule` | **PRUNE** | Implies field masking; no consumer. False data-protection promise. Remove. |
31+
| `field.writeRequiresMasterRead` | **PRUNE** | Governance flag, no consumer. Remove. |
32+
| `field.dataQuality` / `field.auditTrail` | **PRUNE** | Aspirational governance, no runtime. Remove (re-introduce with the feature). |
33+
| `permission.contextVariables` | **PRUNE** | Doc claims runtime RLS evaluation; RLS uses only `current_user.*` built-ins. Misleading — remove. |
34+
| `permission.isProfile` | **PRUNE** | profile-vs-permset never gates anything. Remove (the `profile` type alias already conveys intent). |
35+
| `agent.tenantId` | **ENFORCE-or-PRUNE** | Multi-tenant agent isolation — if agents must be tenant-scoped, wire it in the runtime; else remove. Product call. |
36+
| `skill.permissions` | **ENFORCE-or-PRUNE** | A skill should be restrictable; today unenforced + naming drift (`requiredPermissions`). Enforce at skill-activation, or remove + drop the drift. |
37+
38+
### P1 — naming-drift / duplication *bugs* (authors set them, they silently no-op) → wire or rename
39+
User-visible: documented per the protocol, fails silently.
40+
41+
| Property | Disposition | Why · cost · risk |
42+
|---|---|---|
43+
| `field.referenceFilters` | **WIRE-RENAME** | Lookup dialog reads `lookup_filters`; normalize the key so the documented camelCase works. Net user-facing fix. (renderer side = objectui) |
44+
| `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. |
45+
| `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. |
46+
| `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). |
47+
| `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. |
48+
49+
### P2 — aspirational / duplicate / display surface → PRUNE (narrow-and-true)
50+
No security implication; no roadmap; removing shrinks false surface. Grouped for batch removal.
51+
52+
**object (≈22)** — the largest prune target:
53+
`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).
54+
55+
**field (≈24)** — enhanced-type display config + redundant flags:
56+
`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`.
57+
58+
**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.
59+
60+
**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.)*
61+
62+
**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).
63+
64+
**hook (1)**: `label` **or** `description` — keep one for docs, drop the redundant other.
65+
66+
**role (1)**: `parent` — manager rollup unimplemented (org hierarchy uses `sys_department`). **PRUNE** now; re-introduce with the hierarchy feature, or **DEFER-M2** if roadmapped.
67+
68+
**skill (1)**: `triggerPhrases` — no intent matcher exists. **PRUNE** (remove the misleading "activates this skill" framing) or **ENFORCE** if intent-routing is on the roadmap.
69+
70+
---
71+
72+
## Execution guidance
73+
74+
- **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.
75+
- **Wire-rename** items are bug-fixes; the renderer-side ones (`referenceFilters`, `action.disabled`) land in **objectui**.
76+
- **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.
77+
- After each prune/enforce, the liveness ledger updates and the gate stays green — the loop closes.
78+
79+
## Sequencing recommendation
80+
81+
1. **P0 first** (8 props) — false-compliance is the trust risk; mostly prunes, fast.
82+
2. **P2 object + field prune** (~46 props) — biggest surface reduction, low risk, high signal ("the spec got honest").
83+
3. **P1 wire-rename** — schedule the framework-side ones; file the objectui ones in that repo.
84+
4. **Remaining P2** (flow/tool/action/hook/role/skill) — opportunistic.
85+
86+
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`.

docs/audits/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ dataset `filter`/`format`/`derived`/`dateGranularity`; skill `triggerConditions`
5959
- **Healthiest** (near-total liveness, model schemas): **hook**, **validation**.
6060
- **Worst**: **policy** (100% dead), **portal** (100% dead), **tool** (write-only).
6161

62+
## Disposition plan
63+
- [`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).
64+
6265
## Suggested ADRs
6366
1. **Security enforcement** (cluster #1) — highest priority; either enforce or remove every parsed-but-unenforced security prop.
6467
2. **Finish ADR-0021** (cluster #2) — migrate chart/dashboard/report renderers + Studio off the legacy inline shape.

0 commit comments

Comments
 (0)