Post-#65, mimeType is a property of the fileId — established by the first _attachment@1 record, validated against conflicts on create, and served in download Content-Type resolution. But AttachmentAssociation still carries its own mimeType field (types.ts:45-50), a second per-reference claim that:
- is never validated against the fileId's established mimeType,
- is not part of association identity —
associationEqual (stack.ts:1620-1625) and the SQL PK (sqlite-shared/src/schema.ts:31) both ignore it, so re-associating the same file with a different mimeType is silently dropped as a no-op,
- feeds nothing — download resolution reads the stored
_attachment@1 mimeType, not the association's (confirmed: resolveAttachmentDownloadContentType takes storedMimeType, and no core logic branches on the association field).
Under the properties-vs-perspectives principle it's a property masquerading as a perspective: a second, unvalidated, inert copy of a fact with a single authoritative home.
Decided: delete the field outright
No install base beyond the owner (#57), and nothing consumes the field — so no deprecation dance, no additive-reverse phase. Just remove it. TypeScript will surface every touch point as the discriminated union changes shape.
Work items
Note
The authoritative mimeType path is untouched: _attachment@1.mimeType (the property) and the download resolver remain the single source of truth. This change only removes the redundant, inert copy on the association.
Refs
#65 (mimeType-as-fileId-property), #57 (no install base — change in place), #16 (association-model RFC). From docs/design-assessment-2026-07.md §F1.
Post-#65,
mimeTypeis a property of the fileId — established by the first_attachment@1record, validated against conflicts on create, and served in download Content-Type resolution. ButAttachmentAssociationstill carries its ownmimeTypefield (types.ts:45-50), a second per-reference claim that:associationEqual(stack.ts:1620-1625) and the SQL PK (sqlite-shared/src/schema.ts:31) both ignore it, so re-associating the same file with a different mimeType is silently dropped as a no-op,_attachment@1mimeType, not the association's (confirmed:resolveAttachmentDownloadContentTypetakesstoredMimeType, and no core logic branches on the association field).Under the properties-vs-perspectives principle it's a property masquerading as a perspective: a second, unvalidated, inert copy of a fact with a single authoritative home.
Decided: delete the field outright
No install base beyond the owner (#57), and nothing consumes the field — so no deprecation dance, no additive-reverse phase. Just remove it. TypeScript will surface every touch point as the discriminated union changes shape.
Work items
types.ts: dropmimeTypefromAttachmentAssociation({ kind: 'attachment'; label; fileId })sqlite-shared: stop reading/writingmime_type—rowToAssociation(mappers.ts:37-44) andinsertAssociations(record-logic.ts:553-576). Themime_typeDDL column (schema.ts:29) can stay as a harmless vestige (no migration needed under the schema-in-place policy) or be dropped for new databases — pick one; leaving it is simplestWireRecord/association serialization carriesAssociationverbatim, so this drops out automatically — confirm no fixture orserialize*path hardcodesmimeTypeon an associationmimeTypefrom theattachmentassociation examples (and the wire association response shape in §API Adapter Wire Format)attachmentassociation withmimeTypeNote
The authoritative mimeType path is untouched:
_attachment@1.mimeType(the property) and the download resolver remain the single source of truth. This change only removes the redundant, inert copy on the association.Refs
#65 (mimeType-as-fileId-property), #57 (no install base — change in place), #16 (association-model RFC). From
docs/design-assessment-2026-07.md§F1.