From research/architecture-concerns.md in the repository.

On this page (13 sections)
  1. What this answers
  2. 1. WADM fit and server reuse
  3. 2. Cross-origin embed in 2026
  4. 3. MediaRecorder in 2026
  5. 4. Prior art
  6. 5. Self-hosted identity providers as a sidecar
  7. 6. SKOS vocabulary editing
  8. 7. Admin-GUI-first backends
  9. 8. Upload and processing chain
  10. 9. Embed snippet versioning
  11. 10. Ops for non-technical teams
  12. Decisions this changes
  13. Unverified

Annoudio: architecture concerns

Date of research: 2026-10-09. All claims cite the page that owns them. Dates are "last commit / last release" as shown by the GitHub API on that day.

What this answers

Annoudio is an embeddable audio annotation widget: one Docker container per organisation, annotations stored as W3C Web Annotations, a custom-element player dropped into hand-built sites, WordPress and Omeka S, community accounts inside the container, and annotation bodies that can be text, browser-recorded voice notes, images or video.

Hard constraint (added during research): a largely non-technical team runs the system day to day and wants a GUI for everything (projects, vocabularies, recording catalogue, review queue, theming, user management, and ideally updates and deploys). Every verdict below applies that constraint.

The ten sections answer: (1) does the W3C model fit and can a server be reused; (2) what a cross-origin embed can and cannot do in 2026; (3) what browsers record and play; (4) what prior art exists; (5) which identity provider, if any; (6) how to edit SKOS vocabularies; (7) which admin-GUI backend; (8) the upload and processing chain; (9) how to version the embed snippet; (10) GUI tools to deploy and update the stack.

Terms used throughout:

  • WADM: W3C Web Annotation Data Model. A JSON-LD format for "this body says something about this target".
  • Media Fragment: a URL suffix such as #t=30,60 that names a time range in audio or video.
  • IRI: an internationalised URL. WADM uses IRIs as identifiers.
  • SKOS: a W3C vocabulary for controlled term lists (concepts with labels, broader and narrower links).
  • OIDC: OpenID Connect, the standard login hand-off between an app and an identity provider.

1. WADM fit and server reuse

Finding

WADM covers every structure Annoudio needs. An audio, image or video body is an "External Web Resource" with an id, a format (media type) and a type. The type for audio is Sound, not Audio. A time range on an audio target is a SpecificResource whose selector is a FragmentSelector with conformsTo set to the Media Fragments URL and value such as t=30,60. scope records the page the user was on. rights is an IRI that can sit on the annotation, the body or the target. A tag is a TextualBody with purpose: tagging; a tag that points at a SKOS concept is a SpecificResource body with purpose: tagging and source set to the concept IRI; the two can sit side by side in one body array. The Web Annotation Protocol asks a server for a small set of HTTP behaviours (GET/HEAD/OPTIONS on annotations and containers, POST to create, PUT and DELETE, ETags, Link headers, LDP containers with paging). No existing open-source server is both maintained and fitted with an admin GUI.

Evidence

Verdict for Annoudio

Store annotations as WADM JSON-LD in Postgres jsonb and implement the protocol endpoints yourself (about eight routes; the MUSTs above are the whole checklist). Use type: Sound on audio bodies, FragmentSelector + conformsTo media-frags for time targets, and a two-body array (SpecificResource with source concept IRI + TextualBody with the label) for SKOS tags. Main risk: none of the reusable servers has an admin GUI, so a non-technical team would gain nothing from reuse and would lose the ability to see and moderate annotations in the same GUI as the recordings; Elucidate is dormant, SAS has no auth and no W3C support, miiify is CLI-driven, Hypothesis is a different data model.


2. Cross-origin embed in 2026

Finding

Theming through shadow DOM works today on all engines: CSS custom properties (--name) inherit from the host element into the shadow tree, ::part() lets the host page style named inner elements, and adoptedStyleSheets lets one stylesheet serve many component instances. A script on a third-party page cannot read the container's session: Safari blocks all third-party cookies, Firefox partitions them per site, and Chrome keeps them on by default but has no plan to let embeds rely on them; the Storage Access API needs an iframe, a user gesture and in most browsers a prompt. CHIPS (partitioned cookies) is now in all three engines but only gives a cookie jar scoped to the embedding site, not the container's first-party session. The honest pattern is: anonymous reads via a public CORS API, writes only on a first-party page on the container's domain, with an optional short-lived token passed back on redirect.

Evidence

Verdict for Annoudio

Ship the player as a custom element with an open shadow root, expose theme tokens as --annoudio-* custom properties and named parts, and share one adoptedStyleSheets sheet across instances. Do not try to detect a container session from the embed. Read annotations anonymously through a public CORS endpoint. The "Annotate" action opens a first-party page on the container's domain; after login, redirect back with a short-lived, single-use token in the URL fragment if the embed needs to show "signed in as". Main risk: a product owner expects "comment inline on the host page"; that needs an iframe plus Storage Access prompts on Safari and Chrome, which is a worse user experience than the redirect.


3. MediaRecorder in 2026

Finding

Each engine records a different default. Chrome picks audio/webm;codecs=opus. Firefox picks audio/ogg;codecs=opus. Safari picks audio/mp4 (AAC) and, since Safari 18.4, can also write audio/webm with Opus if asked. MediaRecorder.isTypeSupported() is available in all three since April 2021. For playback, Opus-in-WebM plays everywhere on current versions, but Safari only added Ogg Opus in 18.4 (macOS 15.4, iOS 18.4) and had partial WebM Opus before 17.4, and Chrome lacks AAC in Chromium builds. So a server-side transcode to one format is still required if the org's visitors use older Safari or iOS. The safest single playback format today is AAC in MP4 (.m4a); the smallest is Opus in WebM.

Evidence

Verdict for Annoudio

Record with whatever the browser picks (probe isTypeSupported in the order audio/webm;codecs=opus, audio/ogg;codecs=opus, audio/mp4), upload the raw blob, keep it, and transcode server-side with ffmpeg to AAC-in-MP4 (.m4a) as the single playback file. Serve the original as a second <source> only if its type is WebM/Opus. Main risk: Firefox on a platform without system AAC; mitigate by also emitting Opus/WebM when CPU budget allows and listing both sources.


4. Prior art

Finding

The Omeka S "Annotate" module is a real WADM backend with a protocol endpoint and an admin tab, but it is explicitly "no end user friendly interface", recommends one body and one target per annotation, and documents image xywh fragments, not time fragments. Omeka S media give a stable numeric o:id and an o:original_url, which is what Annoudio needs as the target IRI source. In IIIF land, Clover renders audio/video canvases and VTT "supplementing" annotations as captions and transcript, Ramp is a React IIIF AV player, Mirador 4 still has an open issue for annotations on video, and Annona is image-only. Among audio widgets, wavesurfer.js (regions plugin) and peaks.js (segments) both display and edit time ranges on a waveform and are maintained; Label Studio has an audio region labeler but is a labeling product; Annotorious is image-only; audio-annotator is dead. None stores or renders WADM; Annoudio would map annotations to regions itself.

Evidence

(a) Omeka S

(b) IIIF AV

(c) Audio widgets

Verdict for Annoudio

Reuse wavesurfer.js plus its regions plugin inside the custom element for the read side (regions = annotation time ranges, region-clicked opens the body panel) and for range selection on the first-party annotate page. Keep peaks.js as the fallback if precomputed waveforms for long recordings matter (LGPL applies). Treat Omeka S as a target host, not a backend: the Omeka media o:original_url is the target source, and the Omeka Annotate module can later receive a copy through its /annotations/ protocol endpoint. Main risk: wavesurfer decodes audio in the browser for the waveform; long recordings need server-side peaks or the decoder: none style fallback.


5. Self-hosted identity providers as a sidecar

Finding

Every full identity provider adds at least one more container and a mental model (flows, stages, realms, policies) that a non-technical admin must learn. Authentik and Keycloak are the heaviest (364 MB and 253 MB images, 2 GB RAM recommended) and have the richest admin consoles, but those consoles are built for IT staff. Zitadel is lighter but has no email magic-link primary login. Ory Kratos is headless (you build every screen). Pocket ID is passkey-only. Rauthy is the lightest full OIDC provider with an admin UI and documented magic-link login. lldap and Dex are not user-facing login services for this use case. The reasonable first step is accounts and "login by emailed code" inside the app itself, with an OIDC provider added later.

Evidence

Provider Last release License Image (compressed, amd64) Min RAM (docs) Services OIDC provider Passwordless email Admin UI
Authentik 2026.8.3 2026-09-17 repo "NOASSERTION" (custom) 364 MB (ghcr.io/goauthentik/server) "at least 2 CPU cores and 2 GB of RAM" server + worker + PostgreSQL; Redis removed in 2025.10 yes example blueprint flows-login-email-magic-link.yaml full web admin, flow/stage model
Keycloak 26.8.0 2026-10-01 Apache-2.0 253 MB (quay.io/keycloak/keycloak) "2 GB for smaller production deployments" (heap via MaxRAMPercentage) Keycloak + PostgreSQL (dev-file deprecated in prod) yes not built in; community extension p2-inc/keycloak-magic-link v0.90 full admin console, realm model
Zitadel v4.19.4 2026-10-01 AGPL-3.0 50 MB api + 66 MB login "at least 2 GB RAM" Traefik + API + Login (Next.js) + PostgreSQL yes passkeys; console docs show no email-code primary login console
Ory Kratos v26.2.0 (+ Hydra v26.2.0) 2026-03-20 Apache-2.0 27 MB + 18 MB not stated Kratos + Hydra + SQL DB + your own UI Hydra one-time code by email; "You need a good email delivery provider" none (headless)
lldap v0.6.3 2026-04-30 GPL-3.0 26 MB not stated single; SQLite default no ("For more features (OAuth/OpenID support, ...) you can install" other tools) password reset by SMTP simple web UI
Pocket ID v2.18.0 2026-10-04 BSD-2-Clause 33 MB not stated "one container or one binary", built-in SQLite yes (certified) passkeys only; admin-issued one-time login code yes
Rauthy v0.37.1 2026-10-07 Apache-2.0 35 MB "Hiqlite single instance ~40mb" single; embedded Hiqlite, Postgres optional yes docs list email magic link and passkeys yes
Casdoor v4.18.0 2026-10-07 Apache-2.0 n/a (tag not on Docker Hub) not stated single Go binary + SQL DB (SQLite allowed) yes, also SAML/CAS email and SMS codes web console
Logto v1.44.0 2026-09-30 MPL-2.0 312 MB (svhd/logto) not stated Logto + PostgreSQL yes email/phone verification code; built-in email service is cloud-only console (multi-tenancy cloud-only)
Dex v2.46.0 2026-10-07 Apache-2.0 48 MB not stated single yes n/a; "portal to other identity providers through connectors" none

Sources: https://docs.goauthentik.io/install-config/install/docker-compose ; https://docs.goauthentik.io/core/architecture ; authentik release notes 2025.10 "Removed Redis dependency: authentik no longer uses Redis at all" https://github.com/goauthentik/authentik/blob/main/website/docs/releases/2025/v2025.10.mdx ; https://docs.goauthentik.io/add-secure-apps/flows-stages/flow/flows/ ; https://www.keycloak.org/server/containers ; https://github.com/p2-inc/keycloak-magic-link ; https://zitadel.com/docs/self-hosting/deploy/compose ; https://zitadel.com/docs/guides/manage/console/users ; https://www.ory.com/docs/kratos/passwordless/one-time-code ; https://github.com/lldap/lldap ; https://pocket-id.org/docs/ ; https://pocket-id.org/docs/setup/installation ; https://sebadob.github.io/rauthy/ ; https://github.com/sebadob/rauthy ; https://casdoor.ai/docs/overview/ ; https://docs.logto.io/logto-oss/ ; https://docs.logto.io/end-user-flows/sign-up-and-sign-in/sign-in ; https://github.com/dexidp/dex . Image sizes measured with docker manifest inspect on 2026-10-09; licenses and release dates from the GitHub API on 2026-10-09.

Admin-UI rating for a non-technical operator (judgement, based on the docs above): Authentik and Keycloak consoles expose every concept (flows, stages, policies, realms, clients, mappers) and are built for IT staff; Rauthy, Pocket ID and Casdoor consoles are small and list users, groups and clients; Kratos has no UI; Dex and lldap are not designed as the account system for a public community.

Verdict for Annoudio

Start with accounts inside the app: email + "login by code" (allauth in Django, or better-auth's equivalent in Node), with user management in the same admin GUI as everything else. Do not ship an identity-provider container in v1. If organisations later need single sign-on, add Rauthy (35 MB, embedded DB, admin UI, OIDC) as the sidecar and let the app act as an OIDC client; expose the app itself as an OIDC provider only if a real consumer appears (authlib covers that in Python). Main risk: a magic-code login is only as strong as the mailbox and depends on SMTP deliverability; the team must own a transactional email account from day one.


6. SKOS vocabulary editing

Finding

No maintained JavaScript library exists that edits a SKOS concept hierarchy and exports Turtle or JSON-LD and can be dropped into another admin UI. The maintained editors are full server applications in PHP (TemaTres), Ruby on Rails (iQvoc), Java (VocBench 3, OpenTheso) or Python (Atramhasis, vocabseditor). Skosmos is a browser only; SkoHub Vocabs is a static-site publisher and its editor is archived. A flat hierarchical term list in Annoudio's own admin GUI, with stable concept IRIs and a SKOS export, is the honest first version; it can later be imported into any of these tools.

Evidence

Verdict for Annoudio

Build the vocabulary as a tree of concepts (IRI, prefLabel per language, altLabels, broader, definition) in the admin GUI, and export it as SKOS JSON-LD and Turtle from one endpoint (/vocab/{scheme}.ttl, .jsonld). Mint concept IRIs under the org's domain and never change them; the WADM tag bodies point at them. Import SKOS Turtle so an org that already has a thesaurus in TemaTres or OpenTheso can load it. Main risk: the team invents labels that drift from an external vocabulary; the import path plus exactMatch links keeps that reversible.


7. Admin-GUI-first backends

Finding

Three options give a non-technical team a GUI for records, files, users and roles. Directus is a GUI-first data platform: collections, roles, policies, files and no-code Flows are all edited in the Data Studio, and it runs as one container plus Postgres. Its licence is no longer open source (Monospace Sustainable Core License, free core tier with limits) and it has no magic-link login. Payload CMS is MIT, runs as one Next.js app plus Postgres, models schema in TypeScript (a developer task) but gives editors an admin UI with built-in drafts (_status: draft|published) that is a ready review queue, auth-enabled collections for public community accounts, custom endpoints in-process for JSON-LD, and hooks. Strapi has end-user accounts but no official Docker image and puts Review Workflows behind the Enterprise plan. Django + admin + allauth is the lowest-magic path, but the Django docs say the admin "is not intended for building your entire front end around", so the team's review and vocabulary screens would be custom.

Evidence

Verdict for Annoudio

Choose Payload CMS on Postgres: two services (app + Postgres), MIT, admin UI for recordings, projects, vocabulary concepts, annotations, users and theme settings, a built-in draft/published review queue with per-role publish rights, public community accounts as an auth collection with email verification, and in-process custom endpoints that serialise WADM JSON-LD and the protocol routes. Add magic-code login as a custom auth strategy. Directus is the alternative if GUI schema editing and no-code Flows matter more than licence terms; check the MSCL free-tier limits first. Main risk: Payload's schema lives in code, so adding a field is a developer deploy, not a GUI click.


8. Upload and processing chain

Finding

Uppy with its Tus plugin gives resumable browser uploads; tusd (34 MB image) or @tus/server in-process receives them. ffmpeg transcodes the voice note once (libopus or the native AAC encoder). Transcription on CPU is feasible with the small model: faster-whisper used about 1.5 GB RAM and 1m42s for 13 minutes of audio on an 8-thread desktop CPU; whisper.cpp needs about 0.85 GB for small and 0.39 GB for base. ClamAV wants 3–4 GiB RAM on its own, which is more than the rest of the stack. A Postgres-backed job queue (pg-boss for Node, Procrastinate for Python) avoids a Redis container to run, monitor and back up.

Evidence

  • Uppy uppy@6.0.4 on 2026-09-30, MIT. Tus plugin "brings resumable file uploading with Tus to Uppy by wrapping the tus-js-client"; options endpoint, chunkSize (default Infinity), retryDelays (default [0, 1000, 3000, 5000]); "Transloadit runs tusd in production". https://uppy.io/docs/tus/
  • tusd v2.10.1 on 2026-09-16, MIT; "official reference implementation of the tus resumable upload protocol"; stores on disk, Google Cloud Storage or S3; image tusproject/tusd:v2.10.1 is 34 MB. https://github.com/tus/tusd — @tus/server (tus-node-server, released 2026-09-22, MIT) "A tus server integrated into your existing Node.js server" with FileStore and S3Store, Express and Fastify examples. https://github.com/tus/tus-node-server
  • ffmpeg encoders: "libopus Opus Interactive Audio Codec encoder wrapper"; the native AAC encoder is FFmpeg's default. https://ffmpeg.org/ffmpeg-codecs.html
  • faster-whisper v1.2.1 on 2025-10-31, MIT, Python 3.9+; small model on CPU, int8, beam 5: 1m42s and 1477 MB RAM for 13 minutes of audio; with batch_size=8: 51s and 3608 MB; "Executed with 8 threads on an Intel Core i7-12700K". FFmpeg not required (PyAV bundled). https://github.com/SYSTRAN/faster-whisper
  • whisper.cpp v1.9.5 on 2026-10-06, MIT; memory: tiny ~273 MB, base ~388 MB, small ~852 MB, medium ~2.1 GB, large ~3.9 GB. https://github.com/ggml-org/whisper.cpp
  • ClamAV 1.5.4 on 2026-08-07, GPL-2.0; image clamav/clamav:1.5 148 MB; RAM "Minimum: 3 GiB", "Preferred: 4 GiB"; loading signatures "upwards of 1.2 GiB of RAM"; daily reload "upwards of 2.4 GiB of RAM for a short period". https://docs.clamav.net/manual/Installing/Docker.html
  • pg-boss 12.37.1 on 2026-10-08, MIT: "relies on Postgres's SKIP LOCKED ... Concurrent workers claim jobs without blocking each other, and job processing gets the safety of guaranteed atomic commits." https://github.com/timgit/pg-boss
  • Procrastinate 3.10.0 on 2026-09-23, MIT: "Python 3.10+ distributed task processing library, leveraging PostgreSQL 13+ to store task definitions, manage locks"; Django integration. https://github.com/procrastinate-org/procrastinate
  • Redis 8 alpine image is 37 MB; it is one more stateful service to run and back up (measured 2026-10-09).

Verdict for Annoudio

Uppy + Tus in the annotate page, uploads received in-process (@tus/server with FileStore, or tusd if a second container is acceptable), a pg-boss queue in the same Postgres, and one worker that runs ffmpeg -i in -c:a aac -b:a 96k out.m4a, probes with ffprobe to validate the media type, resizes images, and optionally transcribes with faster-whisper small int8 when the org enables it. Skip ClamAV in v1; the files are audio and images that are never executed and are re-encoded. Main risk: transcription on a 2–4 GB VPS competes with the app for RAM; run it as a separate low-priority worker with a concurrency of one and a per-org toggle.


9. Embed snippet versioning

Finding

Every widely embedded script keeps one stable loader URL and puts the contract in attributes or a global config object. Hypothesis loads https://hypothes.is/embed.js and reads a JSON block or window.hypothesisConfig(); the client ships continuous versions (v1.1766.0) behind that URL. Disqus loads https://SHORTNAME.disqus.com/embed.js and reads disqus_config (page.url, page.identifier). giscus loads https://giscus.app/client.js with data-* attributes and talks to the host via postMessage. YouTube loads https://www.youtube.com/iframe_api and calls onYouTubeIframeAPIReady; it retires methods with dated deprecation notices rather than new URLs. Plausible introduced a new script in October 2025 and kept the old one working for sites that need it. None of them puts a version in the loader path; all of them promise the attributes, not the internals.

Evidence

Verdict for Annoudio

Snippet shape:

<script async src="https://ORG.annoudio.example/embed/v1.js"></script>
<annoudio-player recording="https://ORG.annoudio.example/recordings/123"></annoudio-player>

The contract is: the /embed/v1.js path, the annoudio-player tag name, its attributes (recording, lang, theme), the --annoudio-* CSS tokens and part names, and the DOM events it emits. v1.js is a tiny loader that imports the current hashed bundle, so fixes ship without host edits (the Hypothesis and Plausible pattern). A breaking change gets /embed/v2.js and a new tag attribute set; v1.js keeps serving for years. Main risk: the loader URL is also the org's domain, so a domain change breaks every host page; put the embed host on a stable subdomain from day one.


10. Ops for non-technical teams

Finding

Four GUI tools manage a Docker Compose stack on one VPS. Portainer CE is closest to raw Docker: it edits the compose file in a web editor, has "Update the stack" and "Pull and redeploy" buttons, but its backup covers only Portainer's own configuration, scheduled S3 backup is a paid-edition feature, and upgrading Portainer itself is three CLI commands. Coolify deploys compose from git or raw text with a Deploy button and updates itself from a Settings page. Dokploy deploys compose from git or raw text, backs up named volumes to S3 on a schedule and restores them from the UI, backs itself up to S3, but updates itself through the install script. Komodo runs a Core plus Periphery agents and defines stacks "in the UI, on the host, or in a git repo with auto-deploy on push"; its docs pages on backups could not be read.

Evidence

Verdict for Annoudio

Ship the org container as a Compose stack and document it for Dokploy: a non-technical operator can paste the compose, set the env vars in the UI, press Deploy, schedule volume and database backups to S3, and restore from the same screen. Coolify is the alternative when self-updating from the GUI matters more than volume restore. Portainer stays the choice for an org that already has IT staff. Main risk: Dokploy is pre-1.0 (v0.30.x) and its image is 764 MB; pin a version and test an update on a staging VPS before the org does.


Decisions this changes

  1. Non-technical GUI constraint: every day-to-day object (project, recording, vocabulary concept, annotation, review state, user, theme) must be a record in one admin UI; no CLI-only path for an operator task. This rules out reusing Elucidate, SAS, miiify and Hypothesis h (section 1), rules out headless Kratos and config-heavy Authentik/Keycloak in v1 (section 5), and favours Payload or Directus over a hand-built Django admin (section 7).
  2. WADM: use type: Sound for audio bodies; always FragmentSelector + conformsTo: http://www.w3.org/TR/media-frags/; SKOS tags are a two-body array (section 1).
  3. Protocol endpoints are implemented in-app on Postgres jsonb; the checklist is the MUST list in section 1.
  4. The embed never detects a container session; "Annotate" is a first-party page with redirect back (section 2).
  5. Voice notes are transcoded to .m4a by a worker; the raw blob is kept (section 3).
  6. Read-side widget is built on wavesurfer.js regions inside a custom element (section 4).
  7. Accounts and login-by-code live in the app; no identity-provider container in v1; Rauthy is the later sidecar (section 5).
  8. Vocabularies are a tree in the admin UI with SKOS export and import; no external editor embedded (section 6).
  9. Backend: Payload CMS + Postgres, two services (section 7).
  10. Jobs run in Postgres (pg-boss); no Redis; no ClamAV in v1 (section 8).
  11. Snippet contract is /embed/v1.js + <annoudio-player> attributes, tokens and parts (section 9).
  12. Deployment story targets Dokploy, with Coolify as the alternative (section 10).

Unverified

  • Opus-in-MP4 playback support per browser version. MDN lists MP4 as an Opus container without versions; WebKit source gates Opus in MP4 behind HAVE(AVASSETWRITER_WITH_OPUS_SUPPORTED). Treat Opus-in-MP4 as unsupported for playback until tested.
  • Firefox AAC-in-MP4 playback on Linux depends on system codecs ("relies upon a platform's native support"); not tested here.
  • Omeka S Annotate module: whether a t= time FragmentSelector on a media target round-trips through its API. The README documents xywh only. The GitLab repository is canonical; only the GitHub mirror was read. Its licence is not stated in the GitHub metadata.
  • Authentik's licence (GitHub reports "NOASSERTION"); Directus MSCL free-tier limits (the docs page says higher limits need a paid licence but does not list them); VocBench 3 exact licence variant.
  • Rauthy's email magic-link login: stated on the project docs landing page summary, not confirmed against a configuration reference.
  • Pocket ID SMTP and Postgres support; Casdoor Docker image size (tag v4.18.0 not found on Docker Hub).
  • Keycloak image memory figures beyond "2 GB for smaller production deployments".
  • Komodo backup features and database choice; Dokploy self-update from the web UI (docs show only the install script).
  • Plausible's exact new snippet markup (docs page shows only plausible.init examples).
  • Ramp licence is taken from package.json (ISC); the repo has no LICENSE file.
  • MDN Baseline for CHIPS says "Since December 2025"; BCD lists Safari 26.2. Both were read on 2026-10-09; the Safari minor that re-shipped Partitioned was not cross-checked against WebKit release notes.
  • Chrome's default recorder MIME type was read from the Blink source on main, not from a shipped release tag.