You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(data): enable.files goes live — opt-in gate for the generic Attachments surface (#2727) (#2742)
The last dead ObjectCapabilities flag gets its enforcement contract.
enable.files stays opt-IN (default false) — the Attachments panel is a
new surface, not an existing behavior:
- plugin-audit sys_attachment beforeInsert hook: attachment join rows may
only target objects explicitly declaring enable.files true; absent
block/flag, explicit false, and unknown parent objects all reject
fail-closed with 403 FILES_DISABLED (CLONE_DISABLED/FEEDS_DISABLED
pattern).
- mapDataError maps FILES_DISABLED → 403 with the gated target object
(generic data routes bypass sendError's .status passthrough — the
#2707 lesson applied at introduction time).
- Field.file / Field.image stay independent: they store the file URL in
the record's own column and never create sys_attachment rows.
- Liveness ledger: enable.files dead→live, authorWarn dropped —
ObjectCapabilities is now 100% live; describe() and reference docs
state the real contract; cli lint contract tests re-anchored on
`versioning` as the canonical misleading-dead example.
Verified: unit (4 new gate tests, FILES_DISABLED mapping, lint contract,
32/139/464 suites green), check:liveness + check:api-surface green, and
live E2E on a fresh showcase — presigned 3-step upload → attach to a
files:true probe object 201; attach targeting a no-flag object → 403
FILES_DISABLED; stable download 200. Browser-verified via the console
dev server: panel renders with upload/list/download/delete on the
files:true object and is absent on a no-flag object.
Companion objectui PR ships RecordAttachmentsPanel.
Closes#2727.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|**files**|`boolean`| ✅ |RESERVED (no runtime effect yet) — use Field.file/Field.image for attachments; this flag will gate the future generic Attachments panel|
84
+
|**files**|`boolean`| ✅ |Generic record Attachments panel (sys_attachment). Opt-in: true surfaces the panel and permits attachments targeting this object; otherwise creation is rejected. Field.file/Field.image are independent|
85
85
|**feeds**|`boolean`| ✅ | Record comments/collaboration feed. Default on; explicit false hides the feed UI and rejects new comments for this object |
86
86
|**activities**|`boolean`| ✅ | Record activity timeline (sys_activity mirror of CRUD). Default on; explicit false stops mirroring and hides the timeline |
87
87
|**trash**|`boolean`| ✅ | Enable soft-delete with restore capability |
Copy file name to clipboardExpand all lines: packages/spec/liveness/object.json
+2-4Lines changed: 2 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -165,10 +165,8 @@
165
165
"_authorWarnSkipped": "defaults to true in the schema — the lint can't distinguish author-set-true from the default, so warning here would fire on every object with an enable block. Only default-FALSE booleans are safe to authorWarn."
166
166
},
167
167
"files": {
168
-
"status": "dead",
169
-
"evidence": "no behavior-changing reader in framework or objectui — reserved for the generic Attachments related-list (Salesforce Notes & Attachments parity), tracked in #2727",
170
-
"authorWarn": true,
171
-
"authorHint": "File attachments are modeled with a `Field.file`/`Field.image` (or the sys_attachment object), not this object flag — it enables nothing on its own yet (reserved for the future generic Attachments panel)."
168
+
"status": "live",
169
+
"evidence": "packages/plugins/plugin-audit/src/audit-writers.ts (enforceFilesCapability beforeInsert hook: sys_attachment rows may only target objects declaring enable.files true — 403 FILES_DISABLED otherwise); objectui RecordAttachmentsPanel renders the record Attachments surface (upload/list/download/delete) when the flag is true. Opt-in — spec default false (#2727)."
* Reserved for the generic Attachments related-list (Salesforce
80
-
* "Notes & Attachments" parity). Until that ships, model attachments with
81
-
* `Field.file` / `Field.image` (or relate to `sys_attachment`) — setting
82
-
* this flag alone enables nothing, and the compile-time liveness lint
83
-
* warns on it.
80
+
* Contract (#2727): `true` surfaces the record Attachments panel in the
81
+
* console (upload/list/download/delete over `sys_attachment` join rows)
82
+
* and permits `sys_attachment` rows to target this object; anything else
83
+
* rejects new attachments server-side (403 FILES_DISABLED, enforced at
84
+
* the engine hook seam by plugin-audit — opt-in means explicit).
85
+
* `Field.file` / `Field.image` column attachments are independent of
86
+
* this flag.
84
87
*/
85
-
files: z.boolean().default(false).describe('RESERVED (no runtime effect yet) — use Field.file/Field.image for attachments; this flag will gate the future generic Attachments panel'),
88
+
files: z.boolean().default(false).describe('Generic record Attachments panel (sys_attachment). Opt-in: true surfaces the panel and permits attachments targeting this object; otherwise creation is rejected. Field.file/Field.image are independent'),
86
89
87
90
/**
88
91
* Social collaboration (Comments, Mentions, Feeds) — opt-out.
0 commit comments