Skip to content

Follow-ups from the spec version fix: what is blocked on the embed, and what covers needs first #13

Closed

Description

@hhkaos

Left out of #12 deliberately. Each one is here with what it is actually
blocked on, verified against the live feeds and the embed the reader loads
(v0.6.0), not assumed.

Blocked on <ote-events>, not on this repo

The reader renders nothing: it sets widget.events on <ote-events> and the
widget draws everything. inherit() copies whole event objects, so every
field below already reaches the widget intact — the gap is downstream.

Grepped https://tools.opentechevents.org/embed/v0.6.0/ote-events.js:

  • speakers / affiliation — 0 occurrences. Already live data:
    2 of CoruñaJUG's 11 events carry speakers, and nothing shows them.
    "Ada Lovelace, Analytical Engines" is two fields and must never become one
    string.
  • recordings — 0 occurrences. No live publisher uses it yet.
  • contributing — 0 occurrences. The reader now inherits it feed→event
    (fix: judge feeds by the spec version they declare, not 0.3.0 only #12), so a "suggest a correction" affordance has the data the moment the
    widget can draw one.
  • partOf.offers + offers[].scope (D032) — not handled. partOf is
    used only to group multi-part events; the one scope hit is an HTML
    attribute name in a vendored list. So a part with no offers of its own
    does not fall back to partOf.offers, and an offers entry without
    scope is not read as admission. Latent, not live: no registered feed
    publishes a partOf event today, so nothing is currently displaying a wrong
    price. It becomes a visible wrong answer — a paid talk reading as free — the
    first time a multi-part conference ships on 0.5+.

Worth one issue upstream in ote-events covering all four. Nothing to do here
until the widget supports them, beyond bumping the pinned CDN version in
index.html once it does.

Reader-side, small

  • source is missing from the field toggles. The embed supports a
    source field, but EVENT_FIELD_OPTIONS in app.js doesn't offer it, so
    readers can't turn it on. The other ten ids match.

Reader-side, needs a decision first

  • feed.covers has nothing to attach to yet. It says what window a feed
    claims completeness for, which matters exactly where a reader decides
    whether an event that vanished was cancelled or just aged out of the
    published window. This reader never drops anything — state.savedEvents is
    vestigial and nothing prunes — so there is no wrong inference to correct
    today. The order is: decide whether saved events should be pruned at all,
    then use covers to bound it. Building the consumer of a rule nobody
    applies would be backwards.

Not a gap

The support window moves by itself: npm run check reads the npm registry and
the published event schema and fails when PUBLISHED_SPEC_VERSIONS or
INHERITED_FEED_FIELDS in app.js drift from them. A spec release needs one
line appended, and CI says so when it hasn't been.

Activity

  1. hhkaos commented on Nov 5, 2026

    @hhkaos
    ContributorAuthor

    Corrección y avance.

    source no es un hueco — me equivoqué

    Lo saqué de grepear el bundle minificado, donde "source" aparece por otros
    motivos. En la fuente, FieldKey / ALL_FIELDS en apps/embed/src/attrs.ts
    son exactamente diez: image, when, location, attendance,
    description, price, tags, organizer, eligibility, cfp.
    EVENT_FIELD_OPTIONS en app.js tiene esos diez. No falta ninguno.
    Tachada esa tarea.

    Hecho: #14 sube el widget de v0.6.0 a v0.8.2

    Encontrado al verificar lo anterior: el reader iba dos releases por detrás.
    Trae bump de seguridad de dompurify, URLs e ids no-ASCII sin recodificar,
    e imágenes http:// cayendo al placeholder en vez de dejar marco roto.

    Importante para el resto de esta issue: el widget apunta a OTE 0.4.0
    (oteSpecVersion en su package.json), no a 0.6.0 — el v0.6.0 que estaba
    pineado era la versión del widget, no de la spec. Así que subir el pin no
    acerca ningún campo de 0.5/0.6; eso es trabajo upstream.

    Localizado el hueco de D032, y no está en apps/embed

    Está en packages/preview-feed, que es quien mapea OTE → PreviewEvent:

    • cheapestPrice() (src/format.ts) coge la entrada más barata de
      offers[] que declare precio. Con D032 eso es incorrecto por construcción:
      admission y add-on no son alternativas entre las que elegir, son
      aditivas. Un recargo de 20 € más barato que la entrada gana el reduce.
    • OteJsonEvent (src/json.ts) no declara scope, así que la distinción
      admission / add-on es invisible al mapeo.
    • normalizePartOf() se queda con id, type, name, url y descarta
      partOf.offers
      . Una parte sin offers propio sale sin precio, y no hay
      dato con el que arreglarlo aguas abajo aunque el render quisiera.

    Sigue siendo latente: ningún feed registrado publica eventos con partOf.

    Abro una sola issue upstream con los cinco huecos (speakers/affiliation,
    recordings, contributing, D032) y enlazo aquí.

    Pendiente de decisión tuya

    covers sigue bloqueado en la misma pregunta: ¿los eventos guardados deberían
    podarse cuando desaparecen de un feed? Mientras la respuesta sea "no", covers
    no tiene a qué engancharse.

  2. hhkaos commented on Nov 5, 2026

    @hhkaos
    ContributorAuthor

    Upstream: OpenTechEvents/ote-tools#115 — cubre los cuatro (speakers/affiliation, recordings, contributing, D032) con la localización exacta en packages/preview-feed y apps/embed/src/attrs.ts.

    Estado de esta issue:

    Lo único que queda por decidir en este repo: ¿deben podarse los eventos guardados cuando desaparecen de un feed? Hoy no se poda nada, así que covers no tiene a qué engancharse. Si la respuesta es sí, covers es lo que acota la poda (dentro de la ventana, ausente = retirado; fuera, el feed no afirma nada). Si es no, esta tarea se cierra sin código.

  3. hhkaos commented on Nov 5, 2026

    @hhkaos
    ContributorAuthor

    El reader ya poda, en silencio y por la regla equivocada

    Antes de diseñar nada miré cómo guardan las colecciones, y la premisa de esta
    tarea estaba mal planteada por mí. state.savedEvents es vestigial, sí, pero
    las colecciones reales son state.boards, y boardEvents() resuelve cada
    eventRef contra allEvents() — el feed vivo:

    function boardEvents(board) {
      var refs = board.eventRefs || [];
      return allEvents().filter(function (event) {
        return refs.some(function (item) { return sameRef(item, eventRef(event)); });
      });
    }

    Un evento guardado cuyo publicador lo quita del feed desaparece de tu
    colección sin decir nada.
    Reproducido: dos eventos en Favorites, el
    publicador borra uno, "Actualizar" → Favorites · 1 evento, sin mensaje. La
    eventRef sigue en localStorage para siempre, invisible, apuntando a nada.

    Y lo hace ante cualquier ausencia: envejecido, cancelado, el publicador
    recicló el id, el feed devolvió una respuesta truncada, cambió la URL. Nada
    de eso es "retirado".

    A quién le pasa hoy: eventos.wiki publica 485 eventos y Sarao 180 — los
    publicadores que podan histórico son exactamente estos. Y la colección que más
    lo sufre es "Mis charlas", que por definición acumula charlas pasadas.

    Lo que recomiendo

    El orden correcto no es "añadir poda", es quitar la poda que ya hay:

    1. Snapshot al guardar. eventRefs pasa a llevar el evento, no solo
      {feedUrl, eventId}. Un evento guardado deja de depender de que el feed
      siga llevándolo. Es el prerrequisito de "marcar en vez de borrar": hoy no
      hay nada que marcar porque la tarjeta ya no existe.
    2. Marcar, nunca borrar — tu opción. Con snapshot, covers por fin decide
      algo real: ausente dentro de la ventana que el feed declara completa →
      insignia "Retirado del feed"; fuera de la ventana → nada, porque el feed
      no afirma nada. Sin covers, tampoco nada: un feed sin covers no hace
      ninguna promesa de completitud.
    3. Sin opción configurable. Es una pregunta que el lector no puede
      responder — depende del covers de cada feed, que no ve. Una preferencia
      aquí traslada al usuario una decisión que el dato ya contiene.
    4. Limpieza en Ajustes, acotada a lo que está muerto de verdad: guardados
      cuyo feed ya no está suscrito, y guardados marcados como retirados. Con
      recuento y confirmación.

    No una limpieza de "eventos pasados". Es justo lo que dijiste que quizá sí
    tiene valor — a los que asististe, buscar quién habló — y un evento guardado
    pasado es el único histórico que el reader tiene, porque el feed ya no lo
    lleva. Cuesta unos KB en localStorage y es lo que distingue una colección de
    un filtro. Para no ver pasados en las listas ya está "Solo futuros"; eso es
    vista, no borrado.

    El caso "buscar speakers que hablaron" no pide guardar más: pide que el widget
    renderice speakers, que es OpenTechEvents/ote-tools#115.

  4. hhkaos commented on Nov 5, 2026

    @hhkaos
    ContributorAuthor

    Cerrando. Todo lo que era de este repo está en main (0.11.0, desplegado).

    Punto Resultado
    source en los toggles No existía — error mío al grepear el bundle minificado. ALL_FIELDS son los diez que el reader ya tenía
    Widget pineado por detrás #14 — v0.6.0 → v0.8.2
    covers / eventos guardados #15 — resultó ser otra cosa, ver abajo
    Las dos tareas de release sin guardia #16 — en CLAUDE.md
    speakers / recordings / contributing / D032 Upstream, OpenTechEvents/ote-tools#115

    Lo que cambió de forma por el camino: la premisa de covers estaba mal. El
    reader ya podaba, en silencio — boardEvents() resolvía cada puntero
    contra el feed vivo, así que un evento guardado desaparecía de tu colección
    en cuanto su publicador dejaba de llevarlo, y el puntero se quedaba en
    localStorage apuntando a nada. Desuscribirse de un feed hacía lo mismo. El
    orden correcto no era añadir poda sino quitar la que había: la colección
    guarda el evento, y covers solo decide si la ausencia significa algo.

    Lo que queda es únicamente upstream, y cuando llegue toca trabajo de este
    lado. Abro issue específico para eso en vez de dejar este abierto como
    bitácora: #17.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions