{
  "feature": "media-repository",
  "version": "1.0.0",
  "description": "Upload, store, retrieve, and auto-thumbnail media files. Cache remote media locally, enforce size limits, support multiple storage backends, and run retention cleanup tasks.",
  "category": "data",
  "tags": [
    "media",
    "upload",
    "download",
    "thumbnails",
    "storage",
    "files",
    "images",
    "caching"
  ],
  "actors": [
    {
      "id": "uploader",
      "name": "Uploader",
      "type": "human",
      "description": "User uploading a file to the media repository"
    },
    {
      "id": "downloader",
      "name": "Downloader",
      "type": "human",
      "description": "User or client retrieving a media file or thumbnail"
    },
    {
      "id": "homeserver",
      "name": "Homeserver",
      "type": "system",
      "description": "Server processing media requests and running background tasks"
    },
    {
      "id": "remote_server",
      "name": "Remote Server",
      "type": "external",
      "description": "Origin server for federated media that is cached locally"
    }
  ],
  "fields": [
    {
      "name": "media_id",
      "type": "token",
      "required": true,
      "label": "Unique identifier for the media file on this server"
    },
    {
      "name": "server_name",
      "type": "text",
      "required": true,
      "label": "Homeserver that originally stored the media"
    },
    {
      "name": "upload_name",
      "type": "text",
      "required": false,
      "label": "Original filename provided by the uploader"
    },
    {
      "name": "media_type",
      "type": "text",
      "required": true,
      "label": "MIME type of the uploaded or retrieved file"
    },
    {
      "name": "media_length",
      "type": "number",
      "required": true,
      "label": "File size in bytes",
      "validation": [
        {
          "type": "max",
          "value": 104857600,
          "message": "File exceeds the maximum allowed upload size"
        }
      ]
    },
    {
      "name": "sha256_hash",
      "type": "text",
      "required": false,
      "label": "SHA-256 digest for deduplication and integrity verification"
    },
    {
      "name": "created_ts",
      "type": "datetime",
      "required": false,
      "label": "Timestamp when the media was first stored"
    },
    {
      "name": "last_access_ts",
      "type": "datetime",
      "required": false,
      "label": "Most recent time the media was downloaded or viewed"
    },
    {
      "name": "quarantined",
      "type": "boolean",
      "required": false,
      "label": "Flag indicating media has been blocked due to a policy violation"
    }
  ],
  "states": {
    "field": "media_status",
    "values": [
      {
        "id": "pending",
        "description": "Upload has been initiated but content not yet stored",
        "initial": true
      },
      {
        "id": "stored",
        "description": "Content is persisted and available for retrieval"
      },
      {
        "id": "quarantined",
        "description": "Media has been blocked; access is denied"
      },
      {
        "id": "deleted",
        "description": "Media has been purged by retention policy or administrator",
        "terminal": true
      }
    ],
    "transitions": [
      {
        "from": "pending",
        "to": "stored",
        "actor": "uploader",
        "description": "File content received, validated, and stored"
      },
      {
        "from": "stored",
        "to": "quarantined",
        "actor": "homeserver",
        "description": "Administrator or automated policy quarantines the media"
      },
      {
        "from": "stored",
        "to": "deleted",
        "actor": "homeserver",
        "description": "Retention policy purges unused media"
      }
    ]
  },
  "rules": {
    "uploads": [
      "Uploaded files must not exceed the configured maximum upload size",
      "Image files must not exceed the configured maximum pixel dimension to prevent decompression attacks",
      "Files are deduplicated by SHA-256 hash; identical content reuses the existing storage record"
    ],
    "remote_media": [
      "Remote media is cached locally on first access to reduce repeated federation requests",
      "Remote media downloads are rate-limited to prevent abuse",
      "Only one download of the same remote media may be in progress at a time",
      "Media servers in the configured block list are rejected without network contact"
    ],
    "retention": [
      "Last access timestamps are batched in memory and written to storage periodically",
      "Thumbnails are generated on demand and cached; cached thumbnails reused on subsequent requests",
      "Background retention tasks purge media not accessed within the configured expiration period",
      "Administrators may quarantine media to block access without immediate deletion"
    ]
  },
  "outcomes": {
    "media_uploaded": {
      "priority": 1,
      "given": [
        "file size does not exceed the maximum upload limit",
        "for images: pixel count does not exceed the maximum"
      ],
      "then": [
        {
          "action": "create_record",
          "type": "media",
          "target": "media_store",
          "description": "Media record stored with SHA-256 hash, type, size, and timestamp"
        },
        {
          "action": "emit_event",
          "event": "media.uploaded",
          "payload": [
            "media_id",
            "server_name",
            "uploader_id",
            "media_type",
            "media_length"
          ]
        }
      ],
      "result": "Media is accessible via its URI; can be shared in room messages"
    },
    "media_deduplicated": {
      "priority": 2,
      "given": [
        "uploaded file SHA-256 matches an existing stored file"
      ],
      "then": [
        {
          "action": "emit_event",
          "event": "media.deduplicated",
          "payload": [
            "media_id",
            "existing_media_id"
          ]
        }
      ],
      "result": "Existing media record reused; no duplicate storage consumed"
    },
    "media_retrieved_locally": {
      "priority": 3,
      "given": [
        "media_id belongs to this server",
        "media exists and is not quarantined"
      ],
      "then": [
        {
          "action": "set_field",
          "target": "last_access_ts",
          "description": "Access timestamp updated in memory for batched persistence"
        },
        {
          "action": "emit_event",
          "event": "media.retrieved",
          "payload": [
            "media_id",
            "downloader_id"
          ]
        }
      ],
      "result": "File content returned to requester"
    },
    "remote_media_cached": {
      "priority": 4,
      "given": [
        "media_id belongs to a remote server",
        "media is not in local cache",
        "remote server is not on the block list",
        "download rate limit is not exceeded"
      ],
      "then": [
        {
          "action": "create_record",
          "type": "media",
          "target": "media_cache",
          "description": "Remote media downloaded, validated, and stored in local cache"
        },
        {
          "action": "emit_event",
          "event": "media.remote_cached",
          "payload": [
            "media_id",
            "origin_server"
          ]
        }
      ],
      "result": "Remote media served from local cache; subsequent requests do not contact the origin"
    },
    "thumbnail_generated": {
      "priority": 5,
      "given": [
        "thumbnail not already cached for the requested dimensions and mode",
        "source media is a supported image format"
      ],
      "then": [
        {
          "action": "create_record",
          "type": "thumbnail",
          "target": "thumbnail_cache",
          "description": "Thumbnail image generated and stored in cache"
        },
        {
          "action": "emit_event",
          "event": "media.thumbnail_generated",
          "payload": [
            "media_id",
            "width",
            "height",
            "mode"
          ]
        }
      ],
      "result": "Thumbnail returned to requester; cached for future requests"
    },
    "media_upload_rejected_size": {
      "priority": 6,
      "error": "MEDIA_TOO_LARGE",
      "given": [
        "file size exceeds the configured maximum"
      ],
      "then": [],
      "result": "Upload rejected before storage"
    },
    "media_upload_rejected_pixels": {
      "priority": 7,
      "error": "MEDIA_TOO_MANY_PIXELS",
      "given": [
        "image pixel count exceeds the configured maximum"
      ],
      "then": [],
      "result": "Upload rejected to prevent decompression attack"
    },
    "media_quarantined": {
      "priority": 8,
      "error": "MEDIA_QUARANTINED",
      "given": [
        "media is in quarantined state"
      ],
      "then": [],
      "result": "Access denied"
    },
    "remote_server_blocked": {
      "priority": 9,
      "error": "MEDIA_SERVER_BLOCKED",
      "given": [
        "origin server is on the media download block list"
      ],
      "then": [],
      "result": "Remote media request rejected without contacting the origin"
    }
  },
  "errors": [
    {
      "code": "MEDIA_TOO_LARGE",
      "status": 413,
      "message": "File exceeds the maximum allowed upload size"
    },
    {
      "code": "MEDIA_TOO_MANY_PIXELS",
      "status": 400,
      "message": "Image dimensions exceed the maximum allowed size"
    },
    {
      "code": "MEDIA_NOT_FOUND",
      "status": 404,
      "message": "Media not found"
    },
    {
      "code": "MEDIA_QUARANTINED",
      "status": 404,
      "message": "This media has been removed"
    },
    {
      "code": "MEDIA_SERVER_BLOCKED",
      "status": 403,
      "message": "Media from this server is not permitted"
    }
  ],
  "events": [
    {
      "name": "media.uploaded",
      "description": "A file was successfully uploaded and stored",
      "payload": [
        "media_id",
        "server_name",
        "uploader_id",
        "media_type",
        "media_length"
      ]
    },
    {
      "name": "media.deduplicated",
      "description": "An upload matched an existing file; no new storage was used",
      "payload": [
        "media_id",
        "existing_media_id"
      ]
    },
    {
      "name": "media.retrieved",
      "description": "A stored media file was served to a requester",
      "payload": [
        "media_id",
        "downloader_id"
      ]
    },
    {
      "name": "media.remote_cached",
      "description": "Remote media was downloaded and cached locally",
      "payload": [
        "media_id",
        "origin_server"
      ]
    },
    {
      "name": "media.thumbnail_generated",
      "description": "A thumbnail was generated and cached for a media file",
      "payload": [
        "media_id",
        "width",
        "height",
        "mode"
      ]
    },
    {
      "name": "media.purged",
      "description": "Media was removed by the retention policy or an administrator",
      "payload": [
        "media_id",
        "reason"
      ]
    }
  ],
  "related": [
    {
      "feature": "server-federation",
      "type": "recommended",
      "reason": "Remote media is fetched from origin servers via federation"
    }
  ],
  "agi": {
    "goals": [
      {
        "id": "reliable_media_repository",
        "description": "Upload, store, retrieve, and auto-thumbnail media files. Cache remote media locally, enforce size limits, support multiple storage backends, and run retention cleanup tasks.",
        "success_metrics": [
          {
            "metric": "data_accuracy",
            "target": "100%",
            "measurement": "Records matching source of truth"
          },
          {
            "metric": "duplicate_rate",
            "target": "0%",
            "measurement": "Duplicate records detected post-creation"
          }
        ],
        "constraints": [
          {
            "type": "performance",
            "description": "Data consistency must be maintained across concurrent operations",
            "negotiable": false
          },
          {
            "type": "security",
            "description": "Sensitive fields must be encrypted at rest and never logged in plaintext",
            "negotiable": false
          }
        ]
      }
    ],
    "autonomy": {
      "level": "supervised",
      "human_checkpoints": [
        "before modifying sensitive data fields",
        "before transitioning to a terminal state"
      ],
      "escalation_triggers": [
        "error_rate > 5"
      ]
    },
    "safety": {
      "action_permissions": [
        {
          "action": "media_uploaded",
          "permission": "autonomous"
        },
        {
          "action": "media_deduplicated",
          "permission": "autonomous"
        },
        {
          "action": "media_retrieved_locally",
          "permission": "autonomous"
        },
        {
          "action": "remote_media_cached",
          "permission": "autonomous"
        },
        {
          "action": "thumbnail_generated",
          "permission": "autonomous"
        },
        {
          "action": "media_upload_rejected_size",
          "permission": "supervised"
        },
        {
          "action": "media_upload_rejected_pixels",
          "permission": "supervised"
        },
        {
          "action": "media_quarantined",
          "permission": "autonomous"
        },
        {
          "action": "remote_server_blocked",
          "permission": "human_required"
        }
      ]
    },
    "tradeoffs": [
      {
        "prefer": "data_integrity",
        "over": "performance",
        "reason": "data consistency must be maintained across all operations"
      }
    ],
    "verification": {
      "invariants": [
        "sensitive fields are never logged in plaintext",
        "all data access is authenticated and authorized",
        "error messages never expose internal system details",
        "state transitions follow the defined state machine — no illegal transitions"
      ]
    }
  },
  "extensions": {
    "source": {
      "repo": "https://github.com/element-hq/synapse",
      "project": "Synapse Matrix homeserver",
      "tech_stack": "Python / Twisted async",
      "files_traced": 12,
      "entry_points": [
        "synapse/media/media_storage.py",
        "synapse/media/thumbnailer.py",
        "synapse/media/_base.py"
      ]
    }
  }
}