Release 1.21.0 → PROD - #2119
Merged
Merged
Conversation
… gotchas.md Cuts per-session CLAUDE.md load ~59% (36.5k->15.1k chars). Verbose gotcha paragraphs moved verbatim into tutorials-ims-gotchas.md 'Top Gotchas - full detail'; items with dedicated reference docs (cds-caching, hcql, cap-ai, e2e-coverage) link straight to those. No content deleted.
docs: slim CLAUDE.md Top Gotchas (relocate detail to gotchas.md)
…sses The relocated KG coverage-nudge gotcha carried a bare <mission> token. VitePress compiles docs/**/*.md as Vue SFCs, so the unclosed angle-bracket parsed as an HTML tag and failed 'Deploy Docs to GitHub Pages'. Harmless in CLAUDE.md (not VitePress-built).
…bracket fix(docs): unbreak VitePress build — backtick bare <mission> in gotchas.md
…ntributors/validation/KG/media)
…s (#WS2) Root cause: db/last-dev/csn.json (beforeImage for cds compile.to.hana diff) was updated in the prior commit, so cds build --production saw zero diff and emitted no migration. Workaround: restored csn.json to HEAD~1 baseline, ran cds build --production with the second hana/dest:db task temporarily removed (cds-caching/db/statistics clobber hazard), copied gen/ result to db/src/, restored .cdsrc.json, re-ran deploy to regenerate csn.json correctly.
The migration-clobber workaround (temporarily removing the 2nd hana build task) emitted TutorialValidationRules at a different position in db/last-dev/csn.json than the canonical two-task `cds build --production` that CI's cds-build-staging check runs. Content is byte-identical (pure reordering); regenerated via canonical build. Migration tables unchanged.
…ments Admin OP Phase 1: fix empty Categories / Contributors / Validation facets
…— preserve query, cache-control, slug validation
…filter-input coverage
…land + page-topics; topic-detail CSS
Fix 1 (IMPORTANT): Add loadTopicCorpus() to topics-query.js and make buildTopicDetailPayload accept an optional corpus arg. In publish-topics.js, call loadTopicCorpus once before the loop and pass corpus to each call — eliminates O(topics × full-corpus) redundant DB reads at publish time. Single-slug serve path (srv/server.js) is unchanged (2-arg call, corpus absent).
Fix 2 (MINOR): Remove orphaned topics-map Vue island. Hugo topics layouts were deleted in Task 11; no live mount points remain. Delete src/topics-map/{main.ts,App.vue,ClusterMap.vue,App.test.ts} and vite.config.ts registration/budget plugin; remove island_manifest.json entry (gitignored, regenerates on build); update smoke test marker for /topics/ from id="topics-map" to id="topics-tree-root".
Fix 3 (MINOR): Drop page-topics from IN_SCOPE_PAGES — /topics/ is now served by CAP dynamic topic-index route, not a static page blob. Update page-key-map unit test to assert null for /topics/.
Fix 4 (MINOR): Add CSS for topic-* structural classes emitted by srv/lib/topic-detail-render.js (topic-detail, topic-breadcrumb, topic-detail__header/title/facet, topic-tutorials/concepts/related sections and their items/links) to hugo/assets/css/topics.css. The existing topics-detail/* cluster-detail CSS used topics-* (plural) but the renderer emits topic-* (singular) — genuine styling gap.
feat(topics): tag-tree topics — CAP-served index + detail, concept enrichment, search fix
…son status prop PR #2099 added a `"status": 301` property to the /search route in xs-app.json. @sap/approuter v16 has no route-level redirect verb and rejects the unknown property at boot (xs-app.json/routes/52/status: Additional properties not allowed), crash-looping tutorials-dev-approuter (0/1). Fix mirrors the established sitemap-index-redirect.js pattern: - remove the invalid route from xs-app.json (the deeper /search/<path> srv-api proxy route is untouched) - add approuter/lib/search-redirect.js: a 301 middleware in insertMiddleware.first, before the static/proxy handlers, that redirects the exact /search entry point to /tutorial-navigator/ preserving the query - register it in server.js after sitemapIndexRedirectHandler Verified against @sap/approuter's own validators.validateXsApp: origin/DEV fails at routes/52/status; this commit PASSES. 10 new unit tests green.
…rect-middleware fix(approuter): /search 301 via middleware — unblock DEV approuter boot
…low-up) flattenTopicSlug only collapsed '--'->'-' and lowercased, leaving the spaces, colons and slashes that real Tags.titlePath values carry. Every generated topic slug therefore failed serveHandler's VALID_SLUG guard (/^[a-z0-9][a-z0-9-]*/), so all 152 published topic-<slug> BLOBs 404'd on /topics/<slug> while the tree/index still linked to them. - Add slugifyTopic(): fold every non-[a-z0-9] run to a single hyphen, trim. - flattenTopicSlug delegates to it (subsumes the old '--' collapse). - buildTopicSlugMap slugifies the facet for collision qualification and never emits a leading-hyphen slug when a facetless titlePath collides. - Unit tests assert real-world dirty titlePaths yield VALID_SLUG-safe slugs. Requires a full content republish so stored topic-* keys match the new slugs (render-topics renders server-side).
fix(topics): URL-safe topic slugs so /topics/<slug> serves (#2099 follow-up)
…nal assets (#2103) Adds an admin-gated check that reconciles each planner session's SCHEDULEDSTART against the actual scheduled start times on its external assets and reports any that have drifted apart: - YouTube livestream (videos?part=liveStreamingDetails -> scheduledStartTime) - community.sap.com event (Khoros LiQL -> occasion_data.start_time) Zoom is not checked: the planner carries no readable Zoom start time (bare join link, empty CALENDARINVITE, free-text ZOOMINVITEDETAILS). - srv/lib/devtoberfest-schedule-check.js: pure parsers + comparison + assembly, plus two fetchers behind an injectable fetchImpl seam. Fails soft everywhere: an unreadable leg reports 'unknown', never a spurious 'drift'. Zero cds/db imports. - srv/routes/devtoberfest-schedule-check.js: GET /api/devtoberfest/schedule-check ?edition=<id>&tolerance=<min>, admin-gated (401/403), Cache-Control: no-store. - 25 unit tests covering parsers, tolerance boundaries, statuses, summary counts, fetcher batching/fail-soft, orchestrator wiring. Verified live against Devtoberfest 2026 (87 sessions): community leg resolved 40 event times (39 exact-UTC match, 1 real drift on INT-43 -- planner 22:00Z vs community 07:30Z next day). YouTube leg is fail-soft until the deployed srv resolves YOUTUBE_API_KEY from credstore.
…edule-check feat(devtoberfest): schedule-consistency check across planner + external assets (#2103)
Publishes ACTIVE developer advocates as a cross-container value-help view for the Devtoberfest planner's Session.host field. Joins Advocates -> Users for email; derives a display NAME. Aliases all columns UPPERCASE (consumer synonym resolve rule) and rides the existing tutorial_reader/# roles + HDI leg -- no mta.yaml or binding change. Verified against tutorials-hana DEV via hana-cli (column casing + join + ISACTIVE BOOLEAN predicate).
The tag-tree-topics feature (#2099) added GET /content/topics/:slug, GET /content/topics-index, and POST /content/publish/render-topics to srv/server.js. These are public prod content surfaces mirroring the /content/concepts* routes, not tutorial-draft author-preview endpoints, so they belong in ALLOWLIST_ONLY_ON_SRV (same rationale as concepts/ authors/advocates/puzzles) rather than being mirrored into srv-qa. Fixes the failing postbuild:apps route-drift guard in the unit CI job.
…llowlist fix(ci): allowlist /content/topics* in srv-qa route-drift guard
feat(cross-container): ADVOCATE_VALUE_HELP_V1 view for planner Session.host (#2102)
_guardPublished rejected any PATCH/activation payload that merely *contained* the published flag. Fiori draft activation echoes the whole entity (including an unchanged published:true/false), so a non-SuperAdmin Admin editing only a group/mission description or title was wrongly rejected with 403 'Only SuperAdmin can change the published state'. Compare the incoming published value against the persisted active-row value; reject only on a genuine change. CREATE keeps the false-default exemption. Adds test/admin-published-guard.test.js.
…-guard fix(admin): stop prompting non-SuperAdmin for publish rights on description edits (#2111)
Overview section tags rendered as plain <span>s while the header chips deep-linked to /tutorials/?tag=<slug>. Zip displayTags with displayTagSlugs in tutorial-meta.html and emit <a> anchors matching the header pattern (License stays label-matched + skipped, span fallback when a slug is missing). Add a11y hover/focus styling for the link variant.
…2110) Distinguish live-streamed from prerecorded Devtoberfest sessions with a visual badge and a Format filter across all three views (grid, calendar, schedule table). - Feed: normalize BROADCASTINGPREFERENCE -> 'Live' | 'PreRecorded' | null (srv/lib/devtoberfest-feed.js); select the column in the schedule route. - Shared pure helper broadcasting.ts (badge shape, FORMAT_FILTER_OPTIONS, matchesFormat) so every view renders the tag/filter identically. null/unset preference => no badge and excluded from Live/Prerecorded filters. - Grid, calendar (Month/Week/Day + toolbar), and schedule table all gain the badge + Format filter; filter state deep-links via url-state. - DetailPanel shows a Format meta row. - Unit tests: broadcasting helper, feed normalization, url-state round-trips, and per-view badge/filter behavior.
…ew-tags fix(tutorial): make Overview tags clickable (#2112)
…e-vs-recorded feat(devtoberfest): Live vs Prerecorded session tag + format filter (#2110)
parseTitlePath split on legacy '>'/'--' separators that never appear in live Tags.titlePath data (which uses ' : ' for facet, ' / ' for hierarchy levels), collapsing every tag to facet='' + one whole-path segment — the flat /topics/ tree Tom reported. Now split facet on ' : ' and levels on ' / '. buildTopicSlugMap derives the slug from the FULL titlePath so already-published topic-<slug> BLOB keys/URLs stay byte-stable, with an index suffix for rare collisions (dropped the facet-qualified branch).
fix(topics): nest /topics/ tree by parsing real titlePath separators
Prep for the 1.21.0 PROD release (promotion PR to main follows once this lands in DEV). - .deploy/mta.yaml 1.20.1 → 1.21.0 (minor — feature-bearing DEV delta since 1.20.1) - Refreshed hugo/data/whats_new.json: +27 entries (total 366) summarizing merged PRs since #2078
chore(release): bump MTA 1.20.1 → 1.21.0 + refresh What's New digest
jung-thomas
marked this pull request as ready for review
September 3, 2026 01:33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DEV → main promotion for the 1.21.0 PROD blue-green deploy.
This PR is a draft on purpose. Merge #2118 (chore/release-1.21.0 → DEV) FIRST so DEV carries the
.deploy/mta.yaml1.21.0 bump + refreshed What's New digest. Once #2118 lands in DEV, mark this ready and merge to promote. Merging this before #2118 would ship 1.20.1-versioned content and strand the bump off DEV.Version
.deploy/mta.yaml1.20.1 → 1.21.0 (minor — arrives via chore(release): bump MTA 1.20.1 → 1.21.0 + refresh What's New digest #2118).Highlights since 1.20.1
Deploy
Blue-green to PROD space (manual, from a fresh tree; PROD deploy order planner→tutorials-ims→gameboard). Content publish into PROD via the two-workflow path after swap.