Repository navigation
Description
@opentechevents/[email protected] is on npm (provenance-signed), spec/v0.6 is published, and spec/v0.5 is tagged and frozen. This is the tracking issue for getting the whole ecosystem onto it — every package and app in one place, so nothing is quietly left on 0.4.
What changed, and what it costs you
0.5.0 → 0.6.0 is a no-op for the schemas. Not one field was added, removed or redefined; 0.6 exists to carry four decisions (D039–D042). So for most packages the work is: bump the dependency, change the specVersion you emit, done.
0.4.x → 0.6.0 is where the real work is, and most of the ecosystem is still on 0.4.x. New since 0.4: speakers (with affiliation), recordings, contributing, feed.alternates, feed.covers, partOf.offers + offers[].scope. One deliberate breaking change: multi-part event pricing (D032).
Three decisions with teeth for implementers:
- D039 — JSON only. If any tool accepts or emits YAML, stop. YAML 1.1 resolves unquoted
no/NOto booleanfalse, and both collide with fields we define:NOis Norway incountry's ISO 3166 enum,nois Norwegian intextLanguage. - D040 — an imported event's
idis minted under a domain the community controls;<ics-url>#<UID>only when there is none. The fallback is sticky: never re-mint anidlater, it duplicates the event for every consumer that stored the old one. - D042 — a future 1.0 will freeze validity, not the recommended profiles. The set of warnings is explicitly not a stable interface. Anything building a quality score on it should pin the profile file for the version it tested against.
And one package-level fix worth adopting everywhere: ajvOptions is now exported. The package used to document a bare strict: true, under which no OTE schema in any version has ever compiled. Pass the export, do not assemble options by hand.
Packages
All seven are published at 0.6.0 on npm.
-
validate— validate: dispatch on the declared specVersion, and stop conflating 'unsupported version' with 'invalid document' #95. Dispatches on the declaredspecVersion; exit3for "cannot judge that version", distinct from1"invalid";--versionsand--spec-version. -
import-ics— import-ics: the id it mints, the timezone it invents, and the HTML it copies through #102. D040'sidorder (--id-base, then--source-urlfor<url>#<UID>), both warning that the id is permanent. A link rescued from an HTMLDESCRIPTION— never intoid. -
import-jsonld— import-jsonld: measured losses against a real page — performer, location.address, url from stdin, subEvent #96.performer→speakers(+affiliation),recordings,location.addressunflattened,urlfrom<link rel="canonical">,subEvent→ N documents. -
build-feed— build-feed: 0.5 support, run the feed keywords in --check, and keep partOf.offers consistent (plus: ote-migrate does not exist) #97, exceptote-migrate.contributing/covers/alternates, andcontributinginherited feed→event. -
export-ics/export-rss/export-jsonld— export-ics / export-rss / export-jsonld: map the six fields added since 0.4, and stop judging input by the latest version #103. The six fields mapped, and The exporters and build-feed still judge every feed against the latest spec version #69's "judged by the latest version" fixed in all three. -
discover-feed— discover-feed: apply the settled discovery rules — ote+json canonical, well-known on, embedded out #100.application/ote+jsoncanonical,feed+jsonaccepted with a warning, well-known on by default, embedded removed. -
feed-urls,preview-feed— checked: neither pins or branches on a schema version. Nothing to do. -
ote-migrate— feat(migrate): ote-migrate, for the version bump a sed gets wrong #112, closing build-feed: 0.5 support, run the feed keywords in --check, and keep partOf.offers consistent (plus: ote-migrate does not exist) #97. Scope ended up wider than planned: every published version, not 0.4→0.6. A 0.3 feed and a 0.1 feed both become valid 0.6 by changingspecVersionalone, so the wider range cost nothing — and it is the only version of the tool that helps an adopter whose release has left the window. Validates against the declared version directly rather than throughvalidateDocument, which would have refused out-of-window documents, i.e. exactly the ones that need migrating. The D032 warnings are the part that justifies a package over ased. Published at0.1.0, not0.6.0: it spans versions rather than implementing one.
Apps
-
validator— validator app: expose the version dispatch, speak ote+json, and report how the feed is served #105, in the substantial part. Version dispatch was already exposed;Acceptalready sentote+json; discovery options came with discover-feed: apply the settled discovery rules — ote+json canonical, well-known on, embedded out #100. New: it reports how a feed is served — compression, cache validator, CORS, and two timings (origin-thinking vs transfer, which have different fixes). Live. D042's second half closed in feat(validator): say which profile produced the recommendations #113: the recommendations now name the profile that produced them and say the list is not frozen the way validity is. Two findings there — nopackages/validatechange was needed (each release ships its own profile, so the version checked is the profile version), and the badge does not score on warnings, so D042 never reached it (workers/validator/src/badge.tsis keyed to validity, discovery and reachability only; checked, not assumed). The fetcher's timeouts call a healthy adopter feed unreachable #70's fetcher timeouts landed in fix(validator): wait as long as the ecosystem does, and tell slow from dead #110. -
editor— editor: no form for speakers, recordings, contributing, alternates, covers or multi-part pricing #104, closed by feat(editor): give the six 0.5/0.6 fields a form, so adopters can publish them #106 (c7a24ee). An organizer at the form can now author all six:speakers(+affiliation),recordings,contributing,alternates,covers, andpartOf.offers/scope. Nothing depends on it in code — verified: no package imports it, it is private, and.github/scripts/issue-to-pr.mjsvalidates through the schema rather than a field list, so new fields pass through untouched. -
publish— fix(publish): judge a feed by the version it declares #111, closing The exporters and build-feed still judge every feed against the latest spec version #69.validateDocumentinstead ofvalidateFeed; version notices render above the app rather than in place of it, so the feed still broadcasts.runClidid not need to become async —boot()already was; that note was about the exporters. One unplanned consequence:validateDocumentreaches every embedded version's validators, and a single-outfilebundle inlined all of them (464 KB → 1.3 MB). The samesplitting/outdirconfigapps/validatoruses takesmain.jsto 122 KB, smaller than before the fix. -
embed,preview,dashboard-checks— checked rather than assumed: none pins or branches onspecVersion, andpreview-feedconverts a 0.6 feed carrying all six new fields without complaint. Unknown fields stay legal and are simply not rendered.
Outside this repo
-
ote-reader— hard-rejects anything that is not exactlyspecVersion === '0.3.0'. Worse now than when this was filed: 0.3 left the support window when 0.5.0 and 0.6.0 published on the same day, so it is pinned to a version the kit itself now asks publishers to migrate off. -
ote-template— needs nothing: its workflows call this repo's reusable workflows at@main.
Where this stands
Everything in this repo is on 0.6 and merged. Every package, every app. #69 (#111), #97 (#112), #104 (#106) and #105 (#113) are closed, and #70 went with them in #110.
One item left, and it is not in this repo:
ote-reader— still hard-pinned tospecVersion === '0.3.0', which is now out of the support window. feat(migrate): ote-migrate, for the version bump a sed gets wrong #112 gives it the migration path it did not have when this was filed.
Three things worth knowing that are not anybody's checkbox:
-
The support window is computed, not listed, so publishing two minors in one day slid it to {0.4, 0.5, 0.6} by itself.
Adopter audit, live feeds, 2026-11-04 — the earlier note here said
corunajug.orgwas the one left out of window. That is no longer true, and the adopter it does apply to is a different one:Adopter live specVersionCoruñaJUG 0.5.0 valid, in window — migrated 2026-11-03 eventos.wiki 0.4.0 in window (oldest supported) Sarao 0.4.0 in window Community Builders 0.3.0 out of window — ote-validateexits 3Community Builders' feed (25 events, last updated 2026-08-24) migrates cleanly:
ote-migratetakes it to a valid 0.6.0 and raises 25 D032 warnings, because every event is a part of the recurring "Encuentro mensual" set and carries its ownoffers. Whether those are admission or add-ons is their call, which is exactly what the warnings are for. Still a product decision (reach out, or let the health check flag it), not a code one. -
pnpm-workspace.yamlcarries aminimumReleaseAgeExcludefor@opentechevents/[email protected]withTODO(2026-11-10). pnpm re-adds it on every same-day spec pin; remove it once the release is past the age window. -
@opentechevents/migrateis new, so its first npm release cannot use trusted publishing. npm requires the package to exist before a trusted publisher can be configured: publish it once by hand, then add the trusted publisher in its npm settings. A missing OIDC config fails as a confusing 404.publish.ymldocuments this.
Activity
refactor(validate): take ajv's options from the spec package instead …