Skip to content

chore(deps): bump idna from 3.14 to 3.15 in the uv group across 1 directory - #3004

Merged
CommanderStorm merged 1 commit into
mainfrom
dependabot/uv/uv-d665ee01e3
May 20, 2026
Merged

chore(deps): bump idna from 3.14 to 3.15 in the uv group across 1 directory#3004
CommanderStorm merged 1 commit into
mainfrom
dependabot/uv/uv-d665ee01e3

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github May 19, 2026

Copy link
Copy Markdown
Contributor

Bumps the uv group with 1 update in the / directory: idna.

Updates idna from 3.14 to 3.15

Changelog

Sourced from idna's changelog.

3.15 (2026-05-12)

  • Enforce DNS-length cap on individual labels early in check_label, short-circuiting contextual-rule processing for oversized input while staying compatible with UTS 46 usage.
  • Tidy core helpers: hoist bidi category sets to module-level frozensets (avoiding per-codepoint list construction), simplify length checks, and reuse the shared _unicode_dots_re from idna.core in the codec module.
  • Use raise ... from err for proper exception chaining and switch internal string formatting to f-strings.
  • Allow flit_core 4.x in the build backend.
  • Expand the ruff lint set (flake8-bugbear, flake8-simplify, pyupgrade, perflint) and apply the surfaced fixes; pin lint CI to Python 3.14.
  • Add Dependabot configuration for GitHub Actions.
  • Convert README and HISTORY from reStructuredText to Markdown.
  • Reference CVE-2026-45409 for the 3.14 advisory in place of the initial GHSA identifier.

Thanks to Felix Yan, Stan Ulbrych, and metsw24-max for contributions to this release.

Commits
  • af30a09 Release 3.15
  • 30314d4 Pre-release 3.15rc0
  • 05d4b21 Merge pull request #237 from kjd/convert-docs-to-markdown
  • 2987fdb Convert README and HISTORY from reStructuredText to Markdown
  • 59fa800 Merge pull request #236 from kjd/dependabot/github_actions/actions-f3e34333ea
  • def6983 Merge branch 'master' into dependabot/github_actions/actions-f3e34333ea
  • bbd8004 Merge pull request #234 from StanFromIreland/patch-1
  • edd07c0 Bump github/codeql-action from 3.35.2 to 4.35.2 in the actions group
  • 5557db0 Merge branch 'master' into patch-1
  • f11746c Merge pull request #235 from StanFromIreland/patch-2
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore <dependency name> major version will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
  • @dependabot ignore <dependency name> minor version will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
  • @dependabot ignore <dependency name> will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
  • @dependabot unignore <dependency name> will remove all of the ignore conditions of the specified dependency
  • @dependabot unignore <dependency name> <ignore condition> will remove the ignore condition of the specified dependency and ignore conditions
    You can disable automated security fix PRs for this repo from the Security Alerts page.

Bumps the uv group with 1 update in the / directory: [idna](https://github.com/kjd/idna).


Updates `idna` from 3.14 to 3.15
- [Release notes](https://github.com/kjd/idna/releases)
- [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.md)
- [Commits](kjd/idna@v3.14...v3.15)

---
updated-dependencies:
- dependency-name: idna
  dependency-version: '3.15'
  dependency-type: indirect
  dependency-group: uv
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file python:uv Pull requests that update python:uv code labels May 19, 2026
@CommanderStorm
CommanderStorm merged commit 59b0fb7 into main May 20, 2026
41 checks passed
@CommanderStorm
CommanderStorm deleted the dependabot/uv/uv-d665ee01e3 branch May 20, 2026 11:19
CommanderStorm added a commit to CommanderStorm/NavigaTUM that referenced this pull request Jun 6, 2026
#9)

* fix(server): drop @2x from Martin tile URL so previews actually render (#2897)

Martin's static image rendering serves /style/{name}/{z}/{x}/{y}.png at 512×512
by default. The @2x suffix is a maplibre client convention, not a Martin path,
and returns 404 — so every preview fell back to logo-card.png with the
misleading "Check the connection to the tileserver" warning.

Also fail fast on any non-success status (was: only 400) so a 404's tiny error
body no longer hits the small-response retry branch.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci: keep workflow runs on main from being cancelled (#2902)

Set cancel-in-progress conditional on the ref so concurrent runs are
only cancelled on PR branches. Pushes to main now always run to
completion, giving full visibility into failures across all jobs.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: Faster data pipeline (#2895)

* use more polars

* minor optimisation

* json -> orjson

* change _make_sure_is_safe to work on the serialised output

* change the sitemap io to happen in parallell

* partially migrate to dataframely

* add brotli to speed up network transfers

* use dataframely for usage handling

* use dataframely for tumonline org handling

* use dataframely for tumonline buildings handling

* use dataframely for tumonline room handling

* use dataframely for rf handling

* move the PT handler to dataframely

* fix naming

* lower the compression level for parquet output

* fixup

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* narrow schema dtypes and stabilise content hash

- roomfinder schemas: lock low-cardinality columns to dy.Enum (b_area,
  r_level, default_map_*, MapsSchema.scale/source) — Roomfinder data is
  frozen upstream so the value list doubles as a drift gate
- tumonline schemas: dy.Categorical on address_place/street and
  floor_type/floor_level (TUMonline syncs 2x/month, set is open)
- loaders: read narrowed columns as String first, strip whitespace,
  then cast — preserves the old Pydantic strip behaviour and avoids
  Enum cast errors on stray whitespace (e.g. "Nationalpark Berchtesgaden\n")
- export.py: replace Python hash() with xxhash.xxh64 for the per-entry
  content hash. hash() is salted by PYTHONHASHSEED so the prior values
  changed every build, defeating the purpose as a cache fingerprint

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: satisfy mypy and ruff in data CI

- annotate `path: Path` on the two `_read_csv_typed` helpers
- annotate the three sitemap futures threaded through `_run_pipeline`
- prefix the roomfinder loader docstring with `r"""` (D301)
- add docstrings to the tumonline schema `@dy.rule()` methods (D102)
- add docstrings to the schema-rejection test functions (D103)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(webclient): SEO descriptions, skip link, error-page i18n (#2904)

- Add per-page description frontmatter to all about pages (de+en) and
  surface it via useSeoMeta as description/ogDescription, plus ogType
  and twitterCard for richer social previews.
- Add a localized skip-to-main-content link to default, fullscreen and
  navigation layouts; main now carries id="main-content" + tabindex="-1"
  so keyboard users can bypass the nav and search bar.
- Localize the error page: title, generic error message and the "Go
  home" button now use translation keys instead of hardcoded English,
  so German users no longer hit raw English on non-404 errors.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(server): preserve underscores in search filter slugify (#2899)

* fix(server): preserve underscores in search filter slugify

Filters like ?type=virtual_room or ?type=joined_building returned
0 results because slugify() rewrote `_` to `-`, producing
`virtual-room` / `joined-building` which never match the indexed
type values. Allow `_` to pass through unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(deps): migrate to reqwest 0.13 and oauth2-reqwest (#2903)

Bump reqwest to 0.13 (rename rustls-tls feature to rustls), drop the
bundled reqwest support from oauth2 in favor of the new oauth2-reqwest
0.1.0-alpha.3 wrapper, and bump progenitor-client to 0.14.0 so the local
motis-openapi-progenitor builds against reqwest 0.13.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: lowercase PropertyEdit type tag for consistency (#2901)

The PropertyEdit enum was deserialising the `type` discriminator
as PascalCase (`Name`/`Usage`/`Link`), which is inconsistent with
the rest of the API where tagged enums use lowercase/snake_case.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(server): use Meilisearch native federated search (#2906)

* refactor(server): use Meilisearch native federated search (#1485)

Drop the hand-rolled 3-query merger in favor of the federation API
shipped in Meilisearch v1.10. Rooms- and buildings-facet sub-queries are
now sent in a single `multi-search?federation` request and merged
server-side by `_rankingScore`; per-facet `estimatedTotalHits` come from
`facetDistribution` (with `mergeFacets` set, since the SDK's
`facets_by_index` field cannot deserialise Meilisearch's per-index
keying).

Federation has no per-facet quota, so we over-fetch by a factor of 4 and
let the merger truncate — without this, queries where one facet
dominates the ranking (e.g. `MW1801` returning 14 buildings + 1 room at
the natural cap of 15) would starve the other section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(webclient): add iframe-embeddable map view (#2907)

Closes #1346.

Adds /embed/{id} page that shows the existing DetailsInteractiveMap with
a thin "View details in NavigaTUM" CTA underneath, served on a stripped
embed layout (no app header). Routes are configured to clear
X-Frame-Options and set "frame-ancestors *" so third parties can iframe
them.

The share modal now exposes an "Einbetten / Embed" section with a
copyable iframe snippet pointing at /embed/{id}, mirroring the
Open in / Share / QR Code blocks.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: update js dependencys (#2888)

* js updates

* fix: resolve calendar redirect server-side via location API

The previous client-only redirect chain (/calendar/[id] -> /view/[id] ->
/room/[id]) breaks under Vue 3.5.33 / Nuxt 4.4.2: by the time the second
hop in [view]/[id].vue runs its setup, the page renders with an empty
<main>, so the calendar modal never opens and the e2e test's "Kalender"
heading times out.

Resolve the location's canonical path in the calendar redirect page's
setup, then navigate once with redirectCode 301 to that path with the
calendar[] query. This lets the SSR redirect in a single hop and keeps
SEO-friendly canonical URLs without relying on the multi-step
client-side chain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(deps): update dependency nuxt to v4.3.0 (#2612)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat(webclient): show empty-state when search returns no results (#2909)

feat(webclient): show empty-state for searches with no results

Searches that returned no results previously rendered nothing on the
results page and an empty dropdown in the autocomplete, leaving users
without any indication their query found nothing. Add an explicit
empty-state with a distinct message when filters are active, including
a one-click action to clear the filters.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(data): coordinate edit for `5506.01.607` (#2910)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* fix(search): include POIs in search results (#2908)

* fix(search): include POIs in search results (#1868)

POIs were categorically excluded from search: the data export mapped
`type` -> `facet` for buildings/rooms only, leaving POIs with
`facet: null`, and the server-side merger silently dropped any hit
whose `type` was not in the buildings or rooms allowlist. Group POIs
into the existing rooms section so queries like "Validierungsautomat"
surface their POI entries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: Update OpenAPI spec and types

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* chore(deps): update dependency postcss to v8.5.11 (#2914)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(data): expand ruff lint coverage (#2915)

* chore(data): expand ruff lint coverage

Broaden the ruff `select` from 5 rule families to ~30 to catch a wider
set of bug patterns and modernization opportunities (B, DTZ, I, LOG, G,
N, C4, PERF, SIM, PIE, FLY, RET, RSE, PTH, ARG, FBT, PT, T20, TC, …),
with per-file ignores for pytest-style unused fixture args and a
pep8-naming config that recognises `dy.rule` / pydantic validators.

Fix the resulting violations:
- module-level `_logger = logging.getLogger(__name__)` replaces 73
  root-logger calls across the data pipeline
- remove unused imports, re-sort imports
- `RoomNotFoundException` → `RoomNotFoundError` (N818)
- `os.remove` → `Path.unlink`; tz-aware `datetime.now`; `zip(..., strict=True)`
- mutable default `pl.Utf8()` → module-level constant
- collapse 15 assign-then-return patterns; convert two append loops to
  list comprehensions; merge duplicate elif branches; parenthesise
  mixed `and`/`or` chains

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(data): revert FBT003 fixes that broke polars typing

`pl.when(...).then(value=...)` and `pl.lit(value=...)` are not part of
the polars public signature, so mypy rejected them. Restore the
positional bool calls and silence FBT003 there with `# noqa`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(server): tighten workspace lints (#2913)

* chore(server): tighten workspace lints

Adds a workspace-level clippy lint configuration (restrictions + pedantic
with targeted allows) and fixes the resulting warnings across the server
crate. The motis-openapi-progenitor crate overrides pedantic/restriction
since its source is generator-output that gets overwritten on regeneration.

Notable changes beyond mechanical use-statement and Self-renaming fixes:
- two production panics in setup/meilisearch.rs converted to anyhow::bail!
- Debug impl on SearchResponse was mislabeling Addresses as sites_buildings
- main.rs startup unwraps converted to expect() with rationale
- format!()+= patterns rewritten to write!/writeln! + std::fmt::Write
- TODO-tagged allows on AppliableEdit::apply (property.rs, coordinate.rs)
  where I/O error propagation needs a signature change first

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(deps): bump the npm_and_yarn group across 1 directory with 12 updates (#2917)

Bumps the npm_and_yarn group with 12 updates in the /webclient directory:

| Package | From | To |
| --- | --- | --- |
| [brace-expansion](https://github.com/juliangruber/brace-expansion) | `1.1.12` | `1.1.14` |
| [defu](https://github.com/unjs/defu) | `6.1.4` | `6.1.7` |
| [devalue](https://github.com/sveltejs/devalue) | `5.6.3` | `5.7.1` |
| [h3](https://github.com/h3js/h3) | `1.15.5` | `1.15.11` |
| [lodash](https://github.com/lodash/lodash) | `4.17.23` | `4.18.1` |
| [node-forge](https://github.com/digitalbazaar/forge) | `1.3.3` | `1.4.0` |
| [picomatch](https://github.com/micromatch/picomatch) | `2.3.1` | `2.3.2` |
| [protocol-buffers-schema](https://github.com/mafintosh/protocol-buffers-schema) | `3.6.0` | `3.6.1` |
| [socket.io-parser](https://github.com/socketio/socket.io) | `4.2.5` | `4.2.6` |
| [svgo](https://github.com/svg/svgo) | `4.0.0` | `4.0.1` |
| [tar](https://github.com/isaacs/node-tar) | `7.5.9` | `7.5.13` |
| [yaml](https://github.com/eemeli/yaml) | `2.8.2` | `2.8.3` |



Updates `brace-expansion` from 1.1.12 to 1.1.14
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.14)

Updates `defu` from 6.1.4 to 6.1.7
- [Release notes](https://github.com/unjs/defu/releases)
- [Changelog](https://github.com/unjs/defu/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unjs/defu/compare/v6.1.4...v6.1.7)

Updates `devalue` from 5.6.3 to 5.7.1
- [Release notes](https://github.com/sveltejs/devalue/releases)
- [Changelog](https://github.com/sveltejs/devalue/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/devalue/compare/v5.6.3...v5.7.1)

Updates `h3` from 1.15.5 to 1.15.11
- [Release notes](https://github.com/h3js/h3/releases)
- [Changelog](https://github.com/h3js/h3/blob/v1.15.11/CHANGELOG.md)
- [Commits](https://github.com/h3js/h3/compare/v1.15.5...v1.15.11)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `node-forge` from 1.3.3 to 1.4.0
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.3...v1.4.0)

Updates `picomatch` from 2.3.1 to 2.3.2
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

Updates `protocol-buffers-schema` from 3.6.0 to 3.6.1
- [Commits](https://github.com/mafintosh/protocol-buffers-schema/compare/v3.6.0...v3.6.1)

Updates `socket.io-parser` from 4.2.5 to 4.2.6
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.5...socket.io-parser@4.2.6)

Updates `svgo` from 4.0.0 to 4.0.1
- [Release notes](https://github.com/svg/svgo/releases)
- [Commits](https://github.com/svg/svgo/compare/v4.0.0...v4.0.1)

Updates `tar` from 7.5.9 to 7.5.13
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v7.5.9...v7.5.13)

Updates `yaml` from 2.8.2 to 2.8.3
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.14
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: defu
  dependency-version: 6.1.7
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: devalue
  dependency-version: 5.7.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: h3
  dependency-version: 1.15.11
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: node-forge
  dependency-version: 1.4.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: protocol-buffers-schema
  dependency-version: 3.6.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: socket.io-parser
  dependency-version: 4.2.6
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: svgo
  dependency-version: 4.0.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: tar
  dependency-version: 7.5.13
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: yaml
  dependency-version: 2.8.3
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): update dependency postcss to v8.5.12 (#2918)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat(data): warn on areatree <-> TUMonline name divergence (#2916)

* feat(data): warn on areatree↔TUMonline name divergence

Adds a compile-time check that flags buildings where the areatree name
differs from TUMonline. The original bug: when TUMonline renamed
building 5203 to add HR6/Reisekosten, the change went unnoticed.

The naïve comparison would have produced 331 warnings, mostly noise
(building-code prefixes, operator markers, db-truncation, German
abbreviations, parent-area prefixes). To make the warning useful as a
rename-detection signal, _building_names_equivalent normalises both
sides for:
- TUMonline leading building-code prefixes ((N1), (Südost 1))
- Mid-string and trailing operator markers ((AM)/(NR)/(SZ)/(UMBAU)/…)
- Trailing operator-suffix tokens (LMU/PH/MRI/ForTe)
- Location prefixes the parent area already supplies (Obernach,
  Dürnast, VST.Thalh.-, FMI/, LfL, GP, TUM CS, …) — bilateral
- Areatree-style short-name parentheticals on either side
- Areatree "Gebäudeteil N, " enrichment prefix
- German abbreviation expansion (Str.↔Straße, f.↔für, u.↔und,
  Inst.↔Institut, Geb.↔Gebäude, Werkst.↔Werkstatt, …)
- 40-char DB truncation (both directions)
- AT-enriches-TUM (AT starts with TUM)
- TUMonline reduces to the areatree's explicit short_name

Also adds an embedded-short-name detector in the areatree parser
(process.py) that warns when a name bakes a building code or acronym
that should be expressed via |short_name or visible_id, with hardcoded
skips for institutional brands (TUM, LMU) and TUMonline noise markers.

Curates ~70 areatree edits applying the policy: TUMonline wins on
slight-spelling, real renames, and current official forms; areatree
wins where it preserves addresses, history, colours, or short codes.
Includes real bug fixes: 4119/4120 swapped house numbers and the
'Landwirtschafliche → Landwirtschaftliche' typo.

The remaining 38 warnings are confirmed legitimate signal — they
fire only when TUMonline drift introduces a new divergence worth
human review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* perf(server): drop polars + utoipa yaml to cut build time (#2905)

perf(server): drop polars and utoipa's yaml feature to cut build time

- Replace `polars` (used only as a parquet reader in 3 setup files) with
  the `parquet` crate's row API. Same `Vec<T>` shapes, no behaviour change.
  The `aliases` list column is now flattened in-row instead of via
  `df.explode(...)`.
- Drop the `yaml` feature from `utoipa`; no call site uses it
  (`utoipa-redoc` only needs JSON).

Drops 61 transitive crates from Cargo.lock (728 -> 667).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(deps): update rust crate chrono to v0.4.44 (#2919)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(server): load new upstream rows during bootstrap (#2920)

* feat(data): warn on areatree↔TUMonline name divergence

Adds a compile-time check that flags buildings where the areatree name
differs from TUMonline. The original bug: when TUMonline renamed
building 5203 to add HR6/Reisekosten, the change went unnoticed.

The naïve comparison would have produced 331 warnings, mostly noise
(building-code prefixes, operator markers, db-truncation, German
abbreviations, parent-area prefixes). To make the warning useful as a
rename-detection signal, _building_names_equivalent normalises both
sides for:
- TUMonline leading building-code prefixes ((N1), (Südost 1))
- Mid-string and trailing operator markers ((AM)/(NR)/(SZ)/(UMBAU)/…)
- Trailing operator-suffix tokens (LMU/PH/MRI/ForTe)
- Location prefixes the parent area already supplies (Obernach,
  Dürnast, VST.Thalh.-, FMI/, LfL, GP, TUM CS, …) — bilateral
- Areatree-style short-name parentheticals on either side
- Areatree "Gebäudeteil N, " enrichment prefix
- German abbreviation expansion (Str.↔Straße, f.↔für, u.↔und,
  Inst.↔Institut, Geb.↔Gebäude, Werkst.↔Werkstatt, …)
- 40-char DB truncation (both directions)
- AT-enriches-TUM (AT starts with TUM)
- TUMonline reduces to the areatree's explicit short_name

Also adds an embedded-short-name detector in the areatree parser
(process.py) that warns when a name bakes a building code or acronym
that should be expressed via |short_name or visible_id, with hardcoded
skips for institutional brands (TUM, LMU) and TUMonline noise markers.

Curates ~70 areatree edits applying the policy: TUMonline wins on
slight-spelling, real renames, and current official forms; areatree
wins where it preserves addresses, history, colours, or short codes.
Includes real bug fixes: 4119/4120 swapped house numbers and the
'Landwirtschafliche → Landwirtschaftliche' typo.

The remaining 38 warnings are confirmed legitimate signal — they
fire only when TUMonline drift introduces a new divergence worth
human review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(server): load new upstream rows during bootstrap

`find_keys_which_need_updating` joined `de` with the upstream key/hash
list using an inner join, so only existing keys with a stale hash were
returned. Keys that appeared upstream but were not yet in `de` were
silently dropped, and `download_updates` filtered them out — meaning
new rows in `api_data.json` never reached the database after the first
boot.

Switch to a left join that flags both stale and missing keys; drop the
now-redundant empty-DB fast path and the dead `keys_which_need_removing`
block (those rows are deleted by `cleanup_deleted` in the prior
transaction). Add tests covering missing/changed/unchanged + empty-DB.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Apply suggestion from @CommanderStorm

* Apply suggestion from @CommanderStorm

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(deps): update dependency ts-essentials to v10.2.0 (#2921)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore: re-bless the server snapshot tests (#2925)

fix testss

* fix(webclient): mount details page after /view/* redirect (#2924)

Clicking a /view/{id} link from the home page navigated the URL but
left the home page mounted instead of the detail page, surfacing as
"URL changes but no visible navigation" on production. The trigger:
under nuxt 4.4 / vue 3.5.33 / vue-router 5.0.6, an in-setup
`await navigateTo()` chained to a second hop in the same component
file no longer triggers the destination remount.

Split /view/[id] into its own pure-redirect page (mirrors the
calendar/[id] pattern) so the click flow goes through a different
component than the canonical render, forcing vue-router to unmount
the redirect page and mount the detail page cleanly.

The autogen route names for `pages/view/[id].vue` and
`pages/[view]/[id].vue` collide on the same `view-id` key, so the
new redirect page pins an explicit `view-redirect` name. The
canonical-page validate regex is tightened to only match the actual
canonical prefixes (campus|site|building|room|poi); the redirect
fallback inside the canonical page is gated on `import.meta.server`
so the broken in-setup client-side chain can never run again.

Regression coverage:
- New `regression #2888` test asserts that after clicking Physik
  from `/`, `<main>` no longer contains the home-page `Stammgelände`
  card — the smoking gun for the failed unmount.
- The existing campus and building click tests are tightened to
  assert detail-page-only content (`Anzahl Räume`) and the absence
  of `Stammgelände`. Their previous URL-only / shared-text
  assertions silently passed against the broken build, which is how
  this regression reached production.

Verified against a fresh prod build with the live nuxt 4.4 / vue
3.5.33 / vue-router 5.0.6 deps: all three click-based nav tests
fail before this change and pass after; the rest of the
main+details suite stays green.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(deps): update rust crate reqwest to v0.13.3 (#2929)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* [pre-commit.ci] pre-commit autoupdate (#2927)

updates:
- [github.com/astral-sh/uv-pre-commit: 0.10.7 → 0.11.7](https://github.com/astral-sh/uv-pre-commit/compare/0.10.7...0.11.7)
- [github.com/astral-sh/ruff-pre-commit: v0.15.11 → v0.15.12](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.11...v0.15.12)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(deps): update all non-major dependencies (#2928)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(webclient): prevent submitting unchanged navigation feedback (#2926)

* fix(webclient): prevent submitting unchanged navigation feedback

Track the pre-filled body text and reject submission if the user
hasn't modified it, preventing empty/template-only navigation feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(webclient): capture initialBody in modal instead of per entry point

Capture the pre-filled body when TokenBasedFeedbackModal mounts,
so the unchanged-body check covers all entry points (navigation,
error page, calendar modal) without needing changes in each one.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore(data): batch edits (1 edits) (#2922)

* 1 coordinate edit

* 1 coordinate edit

---------

Co-authored-by: GitHub Actions <actions@github.com>

* fix(data): retry tumonline OAuth token fetch on transient failures (#2931)

The connectum token endpoint occasionally returns a non-token body,
which surfaces as `MissingTokenError`. Because the call lived at module
import, one bad response crashed the whole scraper, the results dir
ended up empty, and the auto-PR step proposed deleting all 5 tumonline
CSVs (this is the workflow's "fail obvious" guardrail, not a bug, but
re-running by hand has been working — so the failures are transient).

Wrap `_generate_oauth_headers()` with `backoff.on_exception` (expo,
max_tries=8) catching both `RequestException` and `OAuth2Error`
(parent of `MissingTokenError`) so a flaky token endpoint retries
with backoff instead of taking the whole nightly job down.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(data): coordinate edit for `5117.EG.102` (#2932)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* Include POIs in search facets (#2912)

* fix(search): include POIs in search results (#1868)

POIs were categorically excluded from search: the data export mapped
`type` -> `facet` for buildings/rooms only, leaving POIs with
`facet: null`, and the server-side merger silently dropped any hit
whose `type` was not in the buildings or rooms allowlist. Group POIs
into the existing rooms section so queries like "Validierungsautomat"
surface their POI entries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: Update OpenAPI spec and types

* refactor(search): split sites/buildings/POIs into 4 first-class facets

Backend changes:
- Federate over 4 facets (site, building, room, poi) via FACETS list,
  not 2 hand-written queries. Sites were previously loaded into Meilisearch
  but never returned because the federation only filtered for room/building.
- ResultFacet enum: split SitesBuildings into Sites + Buildings, add Pois.
- Merger matches on the `facet` field (added to MSHit) instead of the
  `type` field. Drops the `"campus" | "site" | "area"` dead arm and the
  `"poi"` workaround in the rooms arm. Generalized n_visible-freeze logic
  to cover sites > buildings > rooms > pois priority.
- Limits add sites_count + pois_count; query args add limit_sites +
  limit_pois.
- ?type= query param now filters by facet (site|building|room|poi);
  values outside that allowlist are silently dropped.

Frontend changes:
- Drop TYPE_BUCKETS / expandTypes — the backend's facet field already
  buckets subtypes (virtual_room, joined_building, campus, area). Replace
  with FACET_OPTIONS and send raw values.
- SearchSectionList shows up to 4 sections; viewMoreQuery bumps only the
  facet whose "view more" was clicked.
- App/NavigationSearchBar: per-facet expandedFacets set replaces the
  sites_buildings_expanded boolean. As a side fix, expanded sections now
  actually render their hidden entries (previously the button toggled
  keyboard-nav state but the v-if still capped rendering at n_visible).
- search.vue: 4 limit_* params, generalized description i18n.

Data:
- POI export.py: "poi": "room" -> "poi": "poi" (split out of room facet,
  building on #2908 which had funneled POIs into rooms as a tactical fix).

api_types + openapi.yaml updated to match the new schema.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix(search): order facets by relevance, not hardcoded priority

Facets were emitted in a fixed `sites > buildings > rooms > pois`
order, so a single-letter building hit could outrank fully-matching
rooms (e.g. `9201` ranking above 9 strong rooms for `N-1406`).

Track each facet's first-hit position in the ranked Meilisearch
response and assemble the output in that order. Snapshots updated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(search): clean up clippy pedantic warnings post-merge

- Add `#[must_use]` to `Limits::per_facet_total`.
- Import `SITE_FACET`/`BUILDING_FACET`/`ROOM_FACET`/`POI_FACET` instead of
  using absolute paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(webclient): close `<template v-if>` lost in upstream merge

The merge of upstream/main pulled in the no-results empty-state wrapper
in `AppSearchBar.vue` but dropped the closing `</template>` tag,
breaking the Vue compile. Re-add it so the section parses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(search): assert type filter passthrough, not client-side expansion

The 4-facet refactor moved subtype bucketing (joined_building under
building, virtual_room under room) into the server's `facet` field, so
the frontend no longer expands `type=building` to
`type=building&type=joined_building` before calling the API.

Update the e2e assertion accordingly: the URL must contain `type=<bucket>`
exactly once, with no client-side expansion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(search): refresh snapshots against current CDN data

Building/room names in the CDN data have been edited since the last
snapshot regen (e.g. "5502" lost the "Gebäudeteil 2, " prefix). Re-run
`cargo insta test --accept` to absorb the upstream label drift; ranking
and facet ordering are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(details): stub maplibre style so map test isn't gated on prod tileserver

The interactive-map test fails whenever
`https://nav.tum.de/martin/style/navigatum-basemap.json` is unavailable
(currently 404), because MapLibre never fires `load` and the
fullscreen/zoom controls are never added. Intercept the style request
and serve a minimal valid maplibre style — the test still exercises the
control wiring without depending on the upstream tileserver.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(autofix): bring up the full stack before update-screenshots

The update-screenshots job only built the server image and let
playwright start docker compose itself; baseURL then defaulted to
http://localhost:3003 (the server) and every UI test 404'd in <20ms.

Mirror the e2e ui-tests-desktop setup: free disk space, build all
images, install playwright browsers, write the .env, start the stack,
wait for /api + webclient, and run with BASE_URL=http://localhost:3000
and SKIP_WEBSERVER=true so playwright actually drives the webclient.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: update screenshots

* ci(autofix): restore .env before autofix-ci so it doesn't try to commit it

The new test-only .env values were tripping autofix-ci into trying to
commit the placeholder swap. Reset .env (and the existing lockfile
restore) before the autofix step so it only sees real screenshot diffs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: revert autofix-bot's accidental .env overwrite

Restore the placeholder template values; the workflow now resets .env
before autofix-ci runs, so this won't recur.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Apply suggestion from @CommanderStorm

* Apply suggestion from @CommanderStorm

* refactor(search): make ?type= a typed FacetFilter enum

Replaces the silent-drop allowlist in build_meilisearch_filter with a
typed serde enum, so unknown values (e.g. legacy joined_building,
virtual_room) now produce a 400 instead of being dropped into an empty
filter. Also surfaces the allowlist in OpenAPI as a real enum schema.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(data): coordinate edit for `5433` (#2933)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* test(data): show duplicated primary keys when drift-gate fails (#2934)

dataframely's default ValidationError just reports
"primary_key failed for N rows", which doesn't tell us *which* keys
collided when an upstream TUMonline sync introduces duplicates.
``assert_satisfies_schema`` runs the same validation but lists each
duplicated key with its occurrence count so we can patch or escalate
without rerunning the sync locally.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(deps): update rust crate rustls to v0.23.40 (#2936)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(data): coordinate edit for `9377.02.206` (#2940)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* chore(deps): update taiki-e/install-action action to v2.75.25 (#2937)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(data): coordinate edit for `4220.02.111` (#2942)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* chore(renovate): enable lockfile maintenance with automerge (#2943)

Why: keep transitive dependencies fresh between explicit version bumps
without manual intervention.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(webclient): expose Prometheus metrics at /metrics (#2941)

* feat(webclient): expose Prometheus metrics at /metrics

Add prom-client to the Nitro SSR server with default Node.js metrics
and custom SSR metrics (render duration histogram, request counter).
Route labels are normalized to avoid high-cardinality explosions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat(feedback): allow proposing new rooms, buildings, and POIs (#2935)

* feat(feedback): allow proposing new rooms, buildings, and POIs

Extends `POST /api/feedback/propose_edits` with an optional `additions`
field so users can propose entries that don't exist yet — not just edit
existing ones. Three typed variants (room, building, poi) flow through
the same TempRepo → commit → batched PR pipeline as edits.

Validation moves from "CI / drift-gate will catch it" into the request
path: each addition is checked against a `RepoSnapshot` of the on-disk
reference data (areatree, rooms_tumonline.csv, usages_tumonline.csv,
21_pois.yaml, etc.) after the clone but before any writes, so a
malformed addition fails fast with 422 instead of opening a broken PR.

Side-quest: refactor `AppliableEdit::apply` to return
`anyhow::Result<String>` so I/O failures propagate rather than panic
(resolves the TODOs in coordinate.rs and property.rs).

The Python data processor merges the new `additions:` block into the
rooms dict before drift-gate validation, so the same primary-key checks
apply uniformly to scraped + user-added rooms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix(data): make TUMonline/addition room-key collisions a hard error

Previously a user-added room whose key got picked up by TUMonline would
log a warning and silently keep the TUMonline version. That defers the
problem to the drift-gate (or worse, a stale addition lingers forever).

Raise instead: the duplicate has to be resolved by removing the
addition entry, since TUMonline is the source of truth once it ships
the same key.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(data): trim additions schema preamble in 15_patches-rooms_tumonline.yaml

Two lines beat twenty: where the schema lives and what to do when a
collision happens.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(feedback): require coords on every addition variant

Coords are now mandatory for rooms, buildings, and POIs alike — the
field type is `Coordinate`, not `Option<Coordinate>`, so missing-coords
requests fail at JSON deserialization (400) instead of in our validator
(422). Drops the no-longer-reachable `MissingCoords` error variant.

Side polishes:
- LimitedHashMap goes back to `#[derive(Default)]`; the value-type-must-be-
  Default constraint stops biting because the EditRequest fields use
  `#[serde(default = "LimitedHashMap::empty")]` with a constructor that
  doesn't require K/V to be Default.
- BuildingKind picks up `strum::IntoStaticStr` so we can drop a hand-rolled
  `fn label`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(feedback): rstest + insta snapshots for addition tests

- areatree::format_line and insert_under sibling-ordering checks
  collapse from N near-identical fns into one rstest with #[case].
- room/building/poi apply_* tests assert against full-file insta
  snapshots instead of substring greps — diff'ing the snapshot file
  is now the way to review what's written, no re-reading the test.
- Validation failure cases consolidate into one parametric test per
  variant: adding a new AdditionError just means a new #[case] line.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* test(feedback): inline insta snapshots for addition tests

Replaces the 11 .snap files with inline `@r"..."` literals. Reading the
expected output now happens next to the assert; reviewers don't context-
switch to a generated file in another directory. Also lets the rstest
case that needed per-case snapshot names fall back to plain `#[test]`s.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* refactor(feedback): cleanup pass after review

- Coordinate.lat/lon are private again. New `Coordinate::fenced_geojson_feature`
  encapsulates the [lon, lat] ordering + fenced-block formatting, used by both
  the coordinate edit and the new-building summary so that ordering rule lives
  with the type that owns the fields.
- Drop unused RepoSnapshot.coord_ids field + the coordinates.csv read it
  required.
- AreatreeKind derives strum::IntoStaticStr/EnumString/Display + Copy; removes
  hand-rolled as_str/parse and lets format_line take it by value.
- AdditionError gets typed CollisionSource and AdditionVariant enums in place
  of stringly-typed `&'static str` discriminators on IdCollision/WrongParentType,
  plus a constant ALLOWED_PARENT_KINDS list of AreatreeKind values.
- Drop the RoomCode struct; replace with a free `validate_room_code(key) -> &str`.
- TOCTOU: replace `path.exists() { read }` in RepoSnapshot::load with a
  read_to_string match on ErrorKind::NotFound.
- Demote `pub(crate) mod property` to plain `mod property` and rename the
  `appply_set` typo to `apply_set`.
- Tighten the BuildingKind validation match using guard arms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* refactor(feedback): trim verbose comments and reorder addition/edit pass

Move additions before edits in apply_and_gen_description so an edit can target
a freshly-added entry in the same request. Strip narration from comments
introduced in the additions feature, keeping only the rationale where it
isn't obvious from the code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: Update OpenAPI spec and types

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* chore(ci): run cargo-audit only on schedule (#2945)

Advisories still file issues via the daily cron, but PRs no longer
break when a new RUSTSEC entry lands against a transitive dependency
we can't immediately upgrade.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* perf: replace per-request git clone with persistent bare repo + worktrees (#2900)

* perf: replace per-request git clone with persistent bare repo + worktrees

Instead of cloning the full repo over HTTPS on every edit proposal (~30s),
maintain a persistent bare clone and use `git worktree add` (~50ms).
The initial bare clone runs in the background maintenance thread after
MS/DB setup; requests arriving before that fall back to lazy init via
OnceCell.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(webclient): sort metrics imports per autofix-ci

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore(data): batch edits (2 edits) (#2944)

* 1 coordinate edit

* 1 coordinate edit

---------

Co-authored-by: GitHub Actions <actions@github.com>

* feat(data): add usage_id to known_usages.json (#2946)

* feat(data): add usage_id to known_usages.json

Project usage_id from usages_tumonline.csv into known_usages so the
frontend has a stable, precise key per category. Drops the (name_de,
din_277) .unique() since din_277 collides (55 codes / 185 rows) — the
join is now keyed by usage_id-bearing rows. Sort by occurrences DESC,
name_de ASC. The EditProposalModal consumer's typed shape now includes
usage_id.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Apply suggestion from @CommanderStorm

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(data): Synced the data with upstream datasources (#2930)

Synced the data with upstream

Co-authored-by: CommanderStorm <26258709+CommanderStorm@users.noreply.github.com>

* chore(deps): update dependency postcss to v8.5.13 (#2952)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(webclient): merge duplicate useI18n call in PreferencesPopup (#2951)

Resolves the intlify warning "Duplicate `useI18n` calling by local
scope" by destructuring both `t` and `locale` from a single local-scope
useI18n call instead of invoking it twice.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(deps): update all non-major dependencies (#2953)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat(webclient): UI to propose new rooms, buildings, and POIs (#2954)

* feat(data): add usage_id to known_usages.json

Project usage_id from usages_tumonline.csv into known_usages so the
frontend has a stable, precise key per category. Drops the (name_de,
din_277) .unique() since din_277 collides (55 codes / 185 rows) — the
join is now keyed by usage_id-bearing rows. Sort by occurrences DESC,
name_de ASC. The EditProposalModal consumer's typed shape now includes
usage_id.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Apply suggestion from @CommanderStorm

* feat(webclient): UI to propose new rooms, buildings, and POIs

Wires the `additions` field added in #2935 into the feedback flow. A new
"Missing a room, building, or POI?" entry point in the edit-proposal modal
opens a per-kind form that submits in the same payload as edits.

- Zod schema (`additionSchema.ts`) mirrors the Rust validators in
  `server/src/routes/feedback/proposed_edits/addition/{room,building,poi}.rs`,
  so the frontend rejects the same drafts the backend would.
- Room id is composed from PARENT.FLOOR.NUMBER, with the parent prefix
  resolved from the parent's 4-digit alias and the floor list seeded from
  `parent.props.floors[].tumonline`.
- Usage-data layer unified: `useKnownUsages` now exposes `usage_id`,
  `byId`, and `filter`; `<UsageOptionContent>` renders the shared
  label / occurrences / DIN-277 row used by both the search filter and
  the new usage picker.
- Inline map (`LocationPickerInline`) reuses the location-picker maplibre
  setup without the modal chrome.
- ESC now force-closes the expanded global search bar regardless of
  keep-focus flags.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(deps): update dependency @biomejs/biome to v2.4.14 (#2957)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update dependency @biomejs/biome to v2.4.14 (#2958)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* add a simple style validatin step for ci (#2961)

* fix(ci): pin maplibre-gl-style-spec to 24.8.1

v24.8.2 (released May 1) migrated from rollup to rolldown, which broke
the gl-style-validate CLI with a `require("fs")` error in ESM context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): use maplibre style-spec API instead of broken CLI

The gl-style-validate CLI in @maplibre/maplibre-gl-style-spec v24.8.2
is broken due to the rollup->rolldown migration bundling CJS `rw`
package's require("fs") calls into an ESM .mjs output.

Instead of using the CLI, call the library's validateStyleMin API
directly, which is unaffected. Add a lockfile so renovate can manage
the dependency version.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(ci): extract style validation into a script

Move the inline validation logic to map/martin/validate-style.mjs
for readability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Apply suggestion from @CommanderStorm

* Apply suggestion from @CommanderStorm

* refactor(ci): use TypeScript for style validation script

Use Node 22's --experimental-strip-types to run the validation
script as TypeScript directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore(deps): update major-release (major) (#2962)

chore(deps): update major-release

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update all non-major dependencies (#2956)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat(events): pipeline events.csv -> parquet -> postgis on startup (#2955)

* feat(events): pipeline events.csv -> parquet -> postgis on startup

Add an events data type so the map can eventually surface campus
happenings. Events live as a hand-edited CSV in data/sources, get
exported to parquet alongside the rest of the pipeline, and the server
truncate-and-reloads them into a new PostGIS-indexed events table on
boot, mirroring the transportation_stations flow.

The organising_org column is stored free-form; a companion
known_event_orgs.json (TUMonline orgs + accredited HSGs seed list) is
emitted so a future editing UI can constrain the dropdown.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Apply suggestion from @CommanderStorm

* refactor(events): FK organising_org_id to tumonline_orgs

Replace the free-form organising_org TEXT column with an integer
organising_org_id that FKs to a new tumonline_orgs table populated
from the existing orgs-{en,de}_tumonline.csv exports.

The accredited_hsgs.csv seed and known_event_orgs.json export are
removed; HSGs will be merged into tumonline_orgs in a follow-up PR
so the FK keeps working for HSG-organised events.

setup ordering: tumonline_orgs::setup must run before events::setup
because events.organising_org_id references tumonline_orgs(org_id);
the orgs reload uses TRUNCATE ... CASCADE so a stale events row
cannot block a refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(events): events_active view + martin tile source

Add a SQL view that surfaces only events whose visibility window
[starts_at - 2h * days_long, ends_at] contains now(), where
days_long = ceil((ends_at - starts_at) / 1 day) with a floor of 1.

Wire it into Martin as a pg-tables source so the frontend can
render currently-active events as a vector tile layer. Martin's
in-process LRU has no per-source TTL; cache_ttl: 60 plus a 60s
HTTP Cache-Control at the reverse proxy keeps tiles fresh enough
that a newly-active event surfaces within a minute.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Apply suggestion from @CommanderStorm

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* refactor(events): single migration, exporters in export.py, valid martin config

- Squash the three events-related migrations into one
  20260501143400_events.sql so the events table, FK target, and
  events_active view ship together.
- Move export_events_parquet and export_tumonline_orgs_parquet into
  data/processors/export.py and delete the per-domain processor files;
  exporters belong in export.py per project convention.
- Cast the events_active geometry column to geometry(Point, 4326) so
  Martin's geometry_type detection matches the source override.
- Replace the invalid cache_ttl key with cache: disable; Martin's
  per-source cache only supports zoom bounds, not time TTL, and time
  TTL on a now()-dependent view would just serve stale tiles. Add
  geometry_type: POINT to silence the unknown-geometry warning. Comment
  documents the reverse-proxy Cache-Control >= 1h that provides actual
  freshness.
- Verified end-to-end: migrations apply, exporters produce expected
  parquets, and `martin --config map/martin/config.yaml --on-invalid
  abort` accepts the source with no warnings on our keys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* feat(martin): use cache.tile_expiry/tile_idle_timeout for events freshness

Martin does have time-based cache controls (cache.tile_expiry,
cache.tile_idle_timeout — both humantime-parsed); they live on the
top-level `cache:` block, not per-source. Migrate the legacy
top-level cache_size_mb into the structured form and add a 1h
tile_expiry plus 10m tile_idle_timeout. The events_active source
inherits this — no longer needs cache: disable, since the LRU now
expires entries before they go stale.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: Update OpenAPI spec and types

* feat(events): dataframely schemas, drift-gate tests, image/description NOT NULL

Wire the events and tumonline_orgs parquets into the same dataframely
+ drift-gate scaffold the rest of the data pipeline uses. Adds:

- external/schemas/events.py — EventsSchema with rules for RFC 3339
  timestamps, lat/lon range, ends_at >= starts_at (mirrors the DB
  CHECK constraint), positive organising_org_id, non-empty name.
- external/schemas/tumonline_orgs.py — TumonlineOrgsSchema with
  org_id as primary key, positive id rule, non-empty code rule.
- external/loaders/events.py and external/loaders/tumonline_orgs.py
  build the frames from sources, schema-cast on the way out.
- external/schemas/test_schemas_events.py and test_schemas_tumonline_orgs.py
  drift-gate the committed source CSVs and exercise each rule
  individually.

processors/export.py now drives both exports through
Schema.write_parquet, so any drift fails the pipeline at the parquet
boundary instead of at server startup.

Per the contract review: image and description are stipulated to be
present, so they're nullable=false in EventsSchema, NOT NULL in the
events table, and plain String in the Rust loader. New parametrised
test guards both columns against accidental nullability regressions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update events.py

* Simplify docstring for load_tumonline_orgs function

Removed unnecessary details from the docstring of load_tumonline_orgs function.

* Apply suggestion from @CommanderStorm

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Apply suggestions from code review

Co-authored-by: Frank Elsinga <frank@elsinga.de>

* Apply suggestion from @CommanderStorm

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* refactor(events): derive loader dtypes from EventsSchema

The events loader hardcoded schema_overrides instead of deriving dtypes
from EventsSchema.to_polars_schema() like the roomfinder/tumonline
loaders. processors/events.py duplicated manual validation that
EventsSchema rules already cover.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Delete data/processors/events.py

* refactor(events): derive loader dtypes from EventsSchema

The events loader hardcoded schema_overrides instead of deriving dtypes
from EventsSchema.to_polars_schema() like the roomfinder/tumonline
loaders. processors/events.py duplicated manual validation that
EventsSchema rules already cover.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(server): restore sqlx cache and use expect() over unwrap()

- Restore accidentally deleted .sqlx query cache for INSERT INTO de
- Replace unwrap() with expect() to satisfy clippy lint
- Remove duplicate debug_span! line

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* chore(deps): update rust crate serde_with to v3.19.0 (#2964)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update dependency types-requests to v2.33.0.20260503 (#2965)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): lock file maintenance (#2967)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(data): add image for `muc` (#2968)

1 image edit

Co-authored-by: GitHub Actions <actions@github.com>

* chore(deps): update devdependencies (#2966)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update all non-major dependencies (#2963)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* [pre-commit.ci] pre-commit autoupdate (#2969)

updates:
- [github.com/astral-sh/uv-pre-commit: 0.11.7 → 0.11.8](https://github.com/astral-sh/uv-pre-commit/compare/0.11.7...0.11.8)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(deps): update dependency postcss to v8.5.14 (#2970)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update rust crate tokio to v1.52.2 (#2971)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(data): coordinate edit for `2334.EG.309` (#2974)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* chore(data): coordinate edit for `5117.EG.104` (#2975)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* chore(data): batch edits (2 edits) (#2976)

* 1 coordinate edit

* 1 coordinate edit

---------

Co-authored-by: GitHub Actions <actions@github.com>

* chore(data): coordinate edit for `5510.01.012` (#2977)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* chore(deps): update linting (#2979)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update rust crate tokio to v1.52.3 (#2980)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update dependency mypy to v2 (#2981)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update dependency types-pyyaml to v6.0.12.20260510 (#2983)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update devdependencies (#2978)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update rust crate serde_with to v3.20.0 (#2984)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): lock file maintenance (#2986)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update all non-major dependencies (#2963)

* fix(deps): update all non-major dependencies

* fix(server): handle octocrab 0.50 pull request labels type

Agent-Logs-Url: https://github.com/TUM-Dev/NavigaTUM/sessions/4cd2ec09-a2f4-415c-b6a3-328401ee27a0

Co-authored-by: CommanderStorm <26258709+CommanderStorm@users.noreply.github.com>

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: CommanderStorm <26258709+CommanderStorm@users.noreply.github.com>

* chore(data): coordinate edit for `4277.EG.130` (#2991)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* chore(data): coordinate edit for `5501.02.141` (#2988)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* [pre-commit.ci] pre-commit autoupdate (#2992)

updates:
- [github.com/astral-sh/uv-pre-commit: 0.11.8 → 0.11.13](https://github.com/astral-sh/uv-pre-commit/compare/0.11.8...0.11.13)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(deps): update linting (#2993)

* chore(deps): update linting

* ci(e2e): avoid apt dependency install in playwright step

Agent-Logs-Url: https://github.com/TUM-Dev/NavigaTUM/sessions/efa00992-cc69-4373-bf3c-c00469d36807

Co-authored-by: CommanderStorm <26258709+CommanderStorm@users.noreply.github.com>

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: CommanderStorm <26258709+CommanderStorm@users.noreply.github.com>

* fix(deps): update dependency @nuxt/content to v3.14.0 (#3000)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update linting (#3001)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): bump devalue from 5.8.0 to 5.8.1 in /webclient in the npm_and_yarn group across 1 directory (#2996)

chore(deps): bump devalue

Bumps the npm_and_yarn group with 1 update in the /webclient directory: [devalue](https://github.com/sveltejs/devalue).


Updates `devalue` from 5.8.0 to 5.8.1
- [Release notes](https://github.com/sveltejs/devalue/releases)
- [Changelog](https://github.com/sveltejs/devalue/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/devalue/compare/v5.8.0...v5.8.1)

---
updated-dependencies:
- dependency-name: devalue
  dependency-version: 5.8.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): update dependency vue-tsc to v3.3.0 (#2995)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update devdependencies (#3005)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): bump idna from 3.14 to 3.15 in the uv group across 1 directory (#3004)

chore(deps): bump idna in the uv group across 1 directory

Bumps the uv group with 1 update in the / directory: [idna](https://github.com/kjd/idna).


Updates `idna` from 3.14 to 3.15
- [Release notes](https://github.com/kjd/idna/releases)
- [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.md)
- [Commits](https://github.com/kjd/idna/compare/v3.14...v3.15)

---
updated-dependencies:
- dependency-name: idna
  dependency-version: '3.15'
  dependency-type: indirect
  dependency-group: uv
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(data): coordinate edit for `0108.U1.815` (#3007)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@github.com>

* chore(deps): bump nuxt from 4.4.5 to 4.4.6 in /webclient in the npm_and_yarn group across 1 directory (#3002)

chore(deps): bump nuxt

Bumps the npm_and_yarn group with 1 update in the /webclient directory: [nuxt](https://github.com/nuxt/nuxt/tree/HEAD/packages/nuxt).


Updates `nuxt` from 4.4.5 to 4.4.6
- [Release notes](https://github.com/nuxt/nuxt/releases)
- [Commits](https://github.com/nuxt/nuxt/commits/v4.4.6/packages/nuxt)

---
updated-dependencies:
- dependency-name: nuxt
  dependency-version: 4.4.6
  dependency-type: direct:production
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(data): coordinate edit for `9379.02.236` (#3008)

1 coordinate edit

Co-authored-by: GitHub Actions <actions@githu…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file python:uv Pull requests that update python:uv code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant