Release 1.20.0 → PROD - #2058
Merged
Merged
Conversation
The freshness scan judged code blocks in isolation and applied generic best-practice dogma, producing false positives (intentional errors, demo base64 credentials, dev-container setup, npm version-pinning advice that contradicts CAP guidance). - extractCodeBlocks now captures contextBefore/contextAfter (the prose paragraph adjacent to each fence). - extractTutorialContext pulls frontmatter + Prerequisites, fed once at the top of the prompt so the model knows the reader's environment. - SYSTEM_PROMPT now instructs the model to judge blocks in context, respect intentional teaching artifacts (deliberate errors, illustrative demo credentials), and follow SAP/CAP conventions (never suggest pinning @sap/* package versions). - Export SYSTEM_PROMPT/buildUserMessage; add extractor + prompt tests.
- PRECISION: prefer no finding over a speculative one; report each issue once. - OUTPUT vs CODE: never flag staleness/secrets inside illustrative output blocks. - SEVERITY defined by reader impact (fails today / deprecated path / cosmetic). - SCOPE: skip prose, screenshots, product-name currency, deliberate simplifications. - GROUNDING: quote the offending token; flag training-data inferences as Low. Reframes the reviewer as helping the tutorial AUTHOR. Adds prompt-guard tests.
…t-fix freshness: feed tutorial context + SAP-aware rules to the scan
…ckfiles setup-node's 'cache: npm' already warms ~/.npm, but 'npm ci' still spends ~48s extracting/linking 1680 packages + native builds into node_modules on every rebuild run (verified in run 32783495862: cache restored, yet 'added 1680 packages in 48s'). Cache the materialized node_modules (root + hugo-apps) on an exact lockfile key and skip the install on hit. Exact-key only (no restore-keys): skipping 'npm ci' means a mismatched tree would go unreconciled, so any lockfile change must miss and reinstall clean. Safe because neither package.json has install/prepare/postinstall lifecycle scripts -- nothing outside node_modules is produced at install time.
…o-end) Design + specs + tasks for making a single-tutorial rebuild scale with changed slugs instead of the full corpus. Four independently-shippable workstreams, grounded in code research (file:line): - content-delta-publish: mutable ContentCurrent + append-only ContentHistory replaces full-snapshot-per-version + carryForwardUnchanged (~95s server cost) - generated-content-cache: cache hugo/content/tutorials (~25MB) with a correctness-first key (hashes /build feeds + parser source + per-slug source) - single-slug-render: scoped Hugo render (R2 verified coherent) - tutorial-discovery: unmask GraphQL errors + fix App-token org-node auth + loud REST fallback Companion CI win (node_modules cache) shipped separately in #2016.
perf(rebuild): cache node_modules to skip ~48s npm ci on unchanged lockfiles
…a-rebuild Design: slug-targeted delta rebuild (O(changed) end-to-end)
graphqlRequest warn-logged a GraphQL errors/null-data response and returned the null data, so callers dereferenced data.organization/data.repository and threw an opaque TypeError — which the outer catch mistook for an outage and SILENTLY degraded discovery to the slow per-slug REST path (~1400 extra calls, secondary-rate-limit risk) every rebuild. - graphqlRequest now throws a typed GraphqlError carrying the GraphQL error type+message; throws on errors[] or null data. - GraphqlError.isAuthError classifies FORBIDDEN/INSUFFICIENT_SCOPES/permission failures (the App-installation-token org-node gap). - discovery + metadata-batch fallbacks log at ERROR level (once) when the cause is an auth/permission error, so a token-scope regression is visible instead of hidden as latency. Workstream A of the slug-targeted-delta-rebuild design (#2017). The auth fix itself (repo-oriented discovery vs PAT vs App Org:Read) is Workstream B and gated on the real error this now surfaces on DEV. Test: test/unit/github-graphql-error-unmask.test.ts (6 cases).
fix(fetch): unmask GraphQL discovery errors + loud REST fallback
Pure, tested helpers for the slug-targeted fast path: feed fingerprint (catalog/co-completions/tag-labels), sidecar read/write, fast-path eligibility decision, and navEntries-by-slug reconstruction. Fail-open throughout. Nothing calls these yet — the fetch-tutorials.ts reuse wiring (flag-gated, requires a byte-identical DEV diff-verify) + the actions/cache workflow step land next. Test: test/unit/content-cache.test.ts (15 cases).
feat(rebuild): generated-content cache — Workstream C (foundation, draft)
…ated off)
On a slug-targeted run with CONTENT_CACHE_FAST_PATH=true, fetch-tutorials
reuses the previously-generated .md + sidecar nav/author rows for non-target
slugs, skipping composeTutorial/fetchRulesVr/AI-quiz/writeHugoPage — the bulk
of Phase 3's ~56s. Two gates, both required, else full regen:
- actions/cache KEY = parser-source hash (a parser change → cache miss → the
per-slug existsSync guard falls through to recompose)
- runtime feed fingerprint over CAP catalog + tag-labels (nav/mission/tags);
co-completions excluded (empty on warm-cache runs, recommendations are
client-hydrated)
Sidecar (navEntries + authorRows + fingerprint) written to .content-cache/,
cached by the same parser-hashed key as hugo/content/tutorials +
image_dimensions.json. Fail-open throughout; flag defaults OFF so default
behavior is byte-identical to today.
Enabling on DEV (input content-cache=true) + a byte-identical diff-verify
(task 3.6) is the follow-up before flipping the default.
Helper unchanged behavior; content-cache tests green (15).
…n B schema, Workstream D) Mutable current-content table (one row per slug, no version column) + append-only per-(version,slug) history carrying the BLOB for self-contained rollback replay (design.md D1/D2). Mirrored into the QA namespace. Verified: full model compiles + deploys to sqlite::memory:. NEXT (gated, not in this commit): .hdbmigrationtable staging for the two new HANA tables (db/src/ + db/last-dev/ regen via the project's cds-build-staging procedure) + hybrid deploy verify — the version-counter-hazard step. Then write path (dual-write, flag), readers, rollback.
… (Workstream D, flag-gated) commitSession now mirrors freshly-published slugs into the mutable ContentCurrent (UPSERT, one row per slug) + append-only ContentHistory (WRITTEN rows) when CONTENT_DELTA_WRITE_ENABLED=true, alongside the legacy ContentFiles write. Chunked BLOB read mirrors carryForwardUnchanged (raw db.run on HANA for the LOB-locator path, CQL on SQLite). Fail-SAFE: never throws into the commit tx — legacy ContentFiles stays the source of truth until the reader cutover. Tests (SQLite): test/unit/content-delta-dualwrite.test.js (4) — one-row-per-slug, UPSERT on republish, history append per version, flag-off writes neither. Existing commit-path tests still green (carryforward-memory + guard, 12). HANA LOB path is covered by the hybrid publish→rollback test (task 7.4).
feat(rebuild): generated-content fast path — Workstream C wiring (flag-gated, draft)
…h-schema feat(db): Option B schema — ContentCurrent + ContentHistory (Workstream D, draft)
rules.vr answer options like [ ] no / [x] yes rendered as false/true (and a yes/no correctAnswer flipped to a boolean) because the frontmatter serializer emits bare yes/no/on/off tokens under YAML 1.2, which Hugo's YAML 1.1 parser then reads as booleans. jsonify ships those booleans into <script id="tutorial-data"> and the quiz island renders "false"/"true". Add scripts/lib/hugo-yaml.ts (hugoFrontmatterStringify, version: '1.1') so the writer quotes every token a 1.1 reader would misparse, and route all Hugo-frontmatter serializers through it (render-frontmatter, fetch-tutorials, fetch-advocates, author-pages-writer). Regression test round-trips through a YAML 1.1 read.
fix(#2023): stop Hugo coercing yes/no quiz options to true/false
The canonical notify-workflow template (docs/authors/tutorial-repo-dispatch.yml) triggered only on `branches: [main]`. Source repos are a MIXTURE of default branches — most default to `main`, but some (e.g. sap-tutorials/Tutorials) default to `master`. On a master-default repo a main-only trigger never fires, so edits never dispatch `tutorial-updated` and PROD silently goes stale (root cause of the cp-* content-drift incidents; Tutorials was hand-patched by sap-tutorials/Tutorials#24184 but the template itself was never updated — so a future `install-notify-workflows` run would REVERT that fix). - Template now triggers on `[master, main]` (GitHub ignores a listed branch that doesn't exist, so it's safe on every repo regardless of default). - Add a regression guard in the installer unit test asserting the template fires on both branches and never ships a main-only trigger. Propagate to source repos with `npm run install-notify-workflows -- --execute`.
Pre-existing DEV breakage inherited by this PR's CI merge ref: the feature-flag registry drift guard (test/unit/feature-flags-registry.test.js) fails because srv/lib/content-publish-session.js reads process.env.CONTENT_DELTA_WRITE_ENABLED (Workstream D Option-B dual-write) without a matching FEATURE_FLAGS entry. Register it (env, true-enables, default OFF, dev-only) so the guard passes.
fix(notify): dispatch source-repo rebuilds on both master and main
…lag-gated, draft) (#2028) * feat(serve): Option B read cutover for serveStoredSlug (Workstream D, flag-gated) serveStoredSlug serves from the mutable ContentCurrent (WHERE slug=?, no version join) when CONTENT_DELTA_READ_ENABLED=true AND the slug is present, else falls back to the legacy version-pinned ContentFiles snapshot. Per-slug fallback keeps a partially-populated ContentCurrent (pre-full-seed) from 404-ing slugs still in ContentFiles. LOB BLOB read stays on raw db.run for HANA (new hanaCurrentTableName helper). X-Content-Source: db-current | db. Covers the hot path + pages/author/advocate (all route through serveStoredSlug). Special-slug/catalog/embedding readers still use ContentFiles (follow-up 6.2-6.5) — consistent because ContentFiles stays fully populated + authoritative. Tests: test/unit/content-delta-read.test.js (3); content-store legacy suite green (48). * feat(rollback): Option B ContentCurrent clear on rollback (Workstream D, flag-gated) During the dual-write migration window, rollbackHandler now clears ContentCurrent after the manifest flip (when CONTENT_DELTA_WRITE_ENABLED=true) so every read falls back to the just-restored authoritative ContentFiles(target.version) — correct-by-fallback, no per-slug BLOB replay needed. ContentHistory is retained (append-only) for the post-ContentFiles-retirement full history-replay (task 8.4). Fail-safe: never breaks the legacy rollback. Test: content-delta-read.test.js rollback case (publish v1+v2 → rollback v1 → ContentCurrent cleared → serve falls back to ContentFiles D1). 4 tests total green.
…2030) (#2031) Add query-string state sync to the Devtoberfest sessions grid so search, week/track filters, edition, and an open session panel are all shareable and restorable from the URL: /devtoberfest/sessions/?q=<text>&week=<w>&track=<name>&edition=<id>&session=<id> - New pure url-state.ts (parse/serialize + validation), mirroring the calendar's #2006 url-state.ts and the concepts-filter precedent; fail-open (empty/unknown params -> null, never throws). Unit-tested (round-trip, empty/whitespace rejection, unknown-param drop). - App.vue: parse on mount (q/week/track applied synchronously; session applied once the feed loads), history.replaceState on state change, popstate re-sync. App-level integration tests cover restore-from-URL, session-panel open, write-back, and unknown-session fail-open. Closes #2030
… (Workstream D 6.2-6.5, 8.4) (#2032) * feat(serve): migrate __404__ + __nav__ single-slug readers to ContentCurrent (Workstream D 6.2) Adds shared resolveContentBlob helper (ContentCurrent-first when read flag on + present, else legacy ContentFiles active snapshot; raw db.run LOB on HANA). serveNotFound (__404__) + navHandler (__nav__) now route through it — same per-slug fallback as serveStoredSlug, safe on a partially-seeded ContentCurrent. Enumeration readers (nav-fallback/hashes/source-hashes/embeddings) deliberately NOT migrated yet — they enumerate ALL slugs and must wait for the full ContentCurrent seed (task 4.3), else they'd return only the dual-written subset. Tests: content-store (48) + content-delta-read (4) green. * feat(serve): migrate hashesHandler + navHandlerFallback to ContentCurrent (Workstream D 6.3) Both enumerate the active slug set (metadata-only, no BLOB) — switch to ContentCurrent (no version) when CONTENT_DELTA_READ_ENABLED, else legacy ContentFiles active snapshot. Correct once ContentCurrent is fully seeded (task 4.3, running now via a full force rebuild). Tests: 52 green. * feat: complete Option B reader sweep — all readers off ContentFiles-version (Workstream D 6.2-6.5) Migrates the remaining readers to ContentCurrent (read-flag gated, per-slug or enumeration fallback to legacy ContentFiles): - chrome-shell __shell__ (ContentCurrent-first + version fallback; version cache key kept — self-invalidates as manifest version still bumps per publish) - sourceHashesHandler, getTutorialSource (source-column reads) - embedding readContentBuffer + active-slug-set reads (embedding-stats, embedding-reconciliation, cleanup.pruneOrphanEmbeddings, admin seedEmbeddings) No cache re-key needed (6.5): version-keyed caches invalidate on each publish's manifest-version bump regardless of read source. With ContentCurrent seeded (2362 slugs), every reader now serves from it under the read flag. This is the prerequisite for removing carryForwardUnchanged (8.4). Tests: content-store + delta-read + dualwrite + carryforward (58) green. * feat(publish): Option B carry-forward removal + rollback replay (Workstream D 8.4 — the payoff) CONTENT_DELTA_SKIP_CARRYFORWARD (default off) makes publish O(changed slugs): commitSession skips carryForwardUnchanged, so ContentFiles(newVersion) holds only the freshly-published slugs. ContentCurrent (mutable, dual-written) stays complete and serves everything; the ~95s PROD carry-forward disappears. Coupled rollback rework: with carry-forward off, ContentFiles(V) is no longer a complete snapshot, so rollbackHandler now REPLAYS ContentHistory into ContentCurrent (per-slug latest version <= V, chunked LOB read) instead of clear+fallback. detectReverts/history untouched. Adds invalidateContentCache() export (prod busts via cache-generation token on publish; ops/tests that drive publish directly use this). Tests: content-delta-carryforward-skip.test.js (2) — O(changed) publish (ContentFiles holds only changed slugs) + byte-correct multi-version rollback replay. Full content suite 70 green. Enable order (per env): read cutover deployed + ContentCurrent seeded, THEN flip CONTENT_DELTA_SKIP_CARRYFORWARD. * chore(feature-flags): register CONTENT_DELTA_READ_ENABLED + SKIP_CARRYFORWARD env flags Adds the two remaining Option B env flags to the feature-flag registry (CONTENT_DELTA_WRITE_ENABLED was already registered). Satisfies the feature-flags-registry drift guard. dev-only status, default OFF.
The canonical .deploy/mta.yaml approuter builder copied admin-ui, analytics-ui, explore-ui, scanner-ui and data-inspector-ui but never built or copied app/display-app, so static/display-app/ never shipped and the XSUAA-protected /display-app/ route 404'd in every env. Root mta.yaml had the step but that file is not what mbt build uses. Add npm install + vite build + copy of dist/ into static/display-app/, mirroring the analytics-ui pattern (app has base '/display-app/'). Note: the per-app deploy guards (Step 3.5 admin bundle, 3.6 QA navigator, explore-ui check) are hand-curated allowlists and none covers display-app/scanner-ui — an omitted route slips through.
…lags + rollout order) (#2033)
…icalized (#2036) The Option B reader sweep (#2032) added new ContentCurrent read paths in resolveContentBlob/serveStoredSlug (content-store.js) and readContentBuffer (embedding-pipeline.js) mirroring existing ContentFiles reads, but only the pre-existing lines carried the // slug-canonical: marker. The 8 new sibling lookups use the identical caller-canonicalized slug (documented contracts), so mark them consistently rather than adding redundant .toLowerCase(). Fixes check-slug-lookups build guard failure in CI.
Adds a search button (Ctrl+K / Cmd+K) in the admin ToolHeader that opens a ResponsivePopover with a SearchField over a flat, filterable list of all admin pages. Flattens the already role-filtered nav model so authors never see admin-only pages. Navigation dispatch (keyed routes + special deep-link hashes + external href links) is refactored into a shared _navigateToNavItem helper reused by the side nav and the palette.
…p) (#2039) * docs(content-cache): follow-up plan to turn fast path ON by default (Workstream C 3.6/3.8) * feat(content-cache): turn generated-content fast path ON by default Workstream C follow-up (PR #2039). Implements the three items in the plan doc: 1. Byte-identical diff guard (task 3.6): test/unit/content-cache-diff-guard.test.ts exercises the REAL page generator (renderHugoFrontmatter) to prove the properties the fast path's byte-identity rests on — determinism, reused non-target page == full regen, non-target invariance to a target change, and that the feed-fingerprint gate is load-bearing. Network-free; runs every PR. 2. rebuild-content.yml: flip content-cache input default false->true (keep -f content-cache=false opt-out). FIX the repository_dispatch path — compute content_cache_enabled + fast_path in the 'Determine effective rebuild mode' step (was reading inputs.content-cache only, so dispatch always resolved false). CONTENT_CACHE_FAST_PATH env + the cache steps now use those outputs, so author hotfixes (repository_dispatch) get the fast path. Split the combined actions/cache into restore (slug-targeted only, keeps full rebuilds clean of orphan pages) + save (full AND slug-targeted, primes the sidecar). Summary telemetry line added. 3. rebuild-content-qa.yml (task 3.8): mirror — content-cache input (default ON), a 'Determine content-cache mode' step, and split restore/save cache steps with QA channel paths (hugo/content-qa, hugo/data-qa). Refs slug-targeted-delta-rebuild 3.6/3.8.
The month view used grid-template-columns: repeat(7, 1fr), which resolves to minmax(auto, 1fr). The auto min-track equals the widest nowrap chip, so the five weekday columns blew far past the viewport (measured 3951px in a 1122px container) while Sat/Sun collapsed to ~30px and got clipped by the grid's overflow:hidden — you saw ~2 columns and had to zoom out until it was unreadable. - Use repeat(7, minmax(0, 1fr)) + min-width:0 on cells/chips so the seven columns stay equal and the grid never exceeds its container. - Compact each chip to viewer-local time + truncated title (formatViewerTimeShort); speakers move to the hover tooltip instead of eating grid width. - Add an in-place per-day overflow popover: '+N more' opens a dialog listing ALL that day's sessions (closable via backdrop or Escape) instead of navigating away; the day number still opens the full Day view. - Apply the same minmax(0,1fr)+min-width:0 hardening to WeekAgenda, which had the identical latent overflow. Tests: new MonthGrid.test.ts (compact chips + popover), formatViewerTimeShort unit tests, and updated the #2007 speakers guard for the month compaction.
… fixes (#2042) Adds a Chrome-dino-style Easter egg to the /devtoberfest/ home page: the cat (new Kasimir_Types.png) wanders a bounded arena; click/tap plays a meow and, for signed-in players during the active event, awards 5 points/day (once/day, capped at 100/event). Frontend (devtoberfest island): - CatGame.vue rendered below the info; Web Audio meow, wander/hit animation, prefers-reduced-motion + a11y (focusable button, aria-live), score HUD. - Header cat image swapped to kasimir-types.png; new data-attrs wired through main.ts/types.ts/list.html. Award via shared csrfFetch (JSON POST). Backend: - CatGameAwards ledger (composite PK user/event/awardDate → DB-enforced once-per-day) + @cds.persistence.journal + generated migration table. - POST /api/devtoberfest/cat-game/award (authenticated): active-event gating, once-per-day, 100-point cap; srv/lib/cat-game-award.js (pure, tested). - Approuter route block (xsuaa) for the new endpoint. Gameboard contract (fixes pre-existing gap flagged in #2042): - GAMEBOARD_COMPLETION_V1 now surfaces PUZZLE + PETOBERFEST completions (was TUTORIAL-only), so those task types finally score on the leaderboard. - New GAMEBOARD_BONUS_V1 (per-user cat-game points) + gameboard_reader grants. Consumed by the sibling gameboard-srv PR (per-user accrual added to score). Tests: 9 backend (award logic + endpoint), 31 devtoberfest frontend. cds build clean, zero migration/last-dev drift.
…correct stale endpoint path in docs/test (#2042)
…vtoberfest Signups (#2047) The Devtoberfest Signups Analytical List Page opened chart-first with the X-axis bound to the internal integer weekIndex — meaningless to users. This makes the report readable and adds the requested breakdowns: - Readable week axis: add a real, GROUPABLE weekMonday:Date column so the chart groups on it and shows the week's Monday date instead of weekIndex. No portable date-add exists across HANA/SQLite, so weekMonday is supplied per dialect (db/sqlite/native.cds via strftime, db/hana/native.cds via ADD_DAYS) — the CAP-documented per-DB model pattern. The analytics view is split into a JOIN-bearing facts view + a JOIN-free public projection because the compiler refuses to `extend` a view containing a JOIN. - Overall total: @UI.KPI #totalSignups header card (SUM(signups), unfiltered); the AnalyticalTable also renders its grand-total row. - Region breakdown: a "By Region" SelectionPresentationVariant (chart grouped by region); every GroupableProperty (region/role/edition) is also reachable via the chart's built-in dimension drill-down. enrich now derives weekLabel/cumulative from the real weekMonday when present, falling back to weekIndex — keeping weekIndex-grouped reads working. Wiring notes: - package.json requires.db.[development].model=db/sqlite, [hybrid]/[production]=db/hana. - .cdsrc nodejs build task also lists db/hana so the precompiled gen/srv/csn.json bakes the HANA weekMonday (verified: gen csn carries the ADD_DAYS calc). - Specifying requires.db.model defeats cds's compiled-model fast path, so a cold cds.connect.to('db') in dev/tests recompiles the model (~500ms). This is dev/test-only (prod uses the precompiled csn). It exposed a latent 30ms race in test/unit/rebuild-trigger.test.js, fixed there by mocking resolveTenantSettings so the dispatch unit does no real DB work. Verified: cds build --production (HANA hdbview uses ADD_DAYS; runtime csn has weekMonday), sqlite $apply groupby(weekMonday) returns readable dates, prod-profile model resolution loads cleanly, unit suite 8990 passed / 0 failed.
…dar-month-grid fix(devtoberfest-calendar): month grid fits at normal resolution (#2046)
…gnups-report Devtoberfest Signups report: readable week axis, total KPI, region breakdown (#2047)
feat(devtoberfest): Hit the Cat mini-game + gameboard task-type/bonus fixes (#2042)
Mirror the existing /build/verb-definitions pattern:
- anonymous app.get('/build/tags') in srv/server.js reads name+label from
com.sap.developers.ims.Tags ordered by name, 60s Cache-Control, returns
{ tags: [names], buildAt }, 500s on error
- scripts/fetch-tags.ts writes hugo/data/tags.json, warn-and-continue
- wire fetch-tags into build:all next to fetch-verb-definitions
- unit test asserts endpoint returns tags array from seeded rows
feat: add /build/tags tag-taxonomy feed for CI frontmatter validation
feat(devtoberfest): rename "Hit the Cat" → "Tag the Cat" (#2042)
…lay names
ims.Tags.name holds a human display label ("SAP HANA Cloud"), not the
frontmatter-ready category>value slug. The CI frontmatter-unknown-tag
rule matches against category>value keys (e.g. "software-product>sap-hana-cloud").
Derive the correct key by calling titlePathToMdFormat on each row's
titlePath — the same algorithm used by AuthorService/AdminService to
populate the Tags.mdFormat virtual. Sort and deduplicate the resulting
set before emitting.
Unit test updated to seed titlePath values and assert mdFormat output.
fix(build/tags): emit mdFormat (category>value) slugs instead of display names
… axis, hidden weekIndex, labeled total, region/edition/role breakdowns (#2047) Follow-up to #2047. The deployed report was more confusing than before: - weekIndex still leaked as a visible 'Week #' dimension (449/451 internal values) - two competing week dimensions (weekMonday Date + weekIndex int) - the raw Date chart axis rendered a mix of formatted dates and bare day-of-month - the total wasn't clearly labeled Changes: - Add a per-dialect display column weekStartText (HANA TO_VARCHAR 'DY DD MON YYYY' → 'Mon 07 Sep 2026'; SQLite falls back to the ISO Monday date — no name formatter). The chart + table group and sort on the real Date weekMonday but DISPLAY weekStartText via #TextOnly text arrangement, so the axis is a readable category string, not a thinned time axis. - Hide weekIndex entirely (@UI.Hidden, dropped @Analytics.Dimension + removed from GroupableProperties) — kept only to derive weekMonday. Kills the 449/451 leak and the duplicate week dimension. - Keep the labeled 'Total Registrations' KPI header card; drop the redundant ISO 'Week' table column so there is a single week column. - Add By Edition + By Role SelectionPresentationVariants alongside By Region. - Guard weekStartText on both SQLite (unit) and HANA (hybrid) suites. Verified: cds build --production (HANA hdbview carries TO_VARCHAR weekStartText; CSN has text arrangement, hidden weekIndex, 3 breakdown SPVs); 25/25 signup unit tests green.
…eadability fix(admin): readable Devtoberfest Signups report — week axis, labeled total, breakdowns (#2047)
- MTA version bump (minor: DEV carries new features since 1.19.0 — admin page-search palette, Tag the Cat mini-game, /build/tags feed, Devtoberfest deep-links/speakers, tutorial reading prefs, freshness detector). - What's New: +87 entries (PRs merged 2026-08-11 -> 08-27), total 321.
chore(release): bump MTA 1.19.0 → 1.20.0 + refresh What's New digest
An author-disabled section wrapped in a multi-line HTML comment (e.g. <!-- ## Prerequisites ... -->) was mis-parsed: extractSection lifted the commented heading out as a real section (leaking its closing --> into the field) and extractIntro stranded the opening <!-- into the intro. That unterminated comment then swallowed every step when Hugo rendered the page (root cause of the codejam-events-process-1-bah blank-steps break). Add fence-aware commentLineFlags(); mask multi-line-commented lines before section detection in extractFrontmatter and drop them in extractIntro. Single-line comments (<!-- description -->, image directives) are untouched. Verified: codejam original composes to 6 steps with empty prereq + balanced intro via the parser alone; full corpus genuinely-broken count 14 -> 13 (only codejam removed, no new breakage); 186 existing parser tests + 5 new pass.
…rser fix(parsers): comment-aware section/intro extraction
…s despite feed drift
QA rebuilds ran ~10min (vs prod ~90s) for a single-slug preview. Root
cause: the content-cache fast path (decideFastPath) disables on a feed
fingerprint mismatch (catalog/tag-labels), forcing a full regen of all
~2100 tutorials. QA rebuilds are infrequent while prod republishes on
every merge, so by each QA run the catalog has drifted and the
fingerprint almost always mismatches — chronically defeating the fast
path. (The slug-filter Phase-2 scoping already works on QA; the full
regen, not discovery, was the cost.)
Add decideFastPath({ allowFeedDrift }) and set it for channel === 'qa'
only. On QA slug-targeted runs the fast path now reuses cached
non-target pages despite feed drift (the target slug is always
regenerated). Trades slightly-stale nav/tags on OTHER preview pages
(corrected on the next full QA rebuild) for a ~90s targeted preview.
Prod keeps strict feed-freshness (allowFeedDrift defaults false).
Tests: +4 decideFastPath cases (allowFeedDrift eligible on drift; still
requires sidecar + slug-targeted). 18 content-cache tests pass.
…-drift perf(qa): reuse cached non-target content on QA slug-targeted rebuilds despite feed drift
…rry-pick) for 1.20.0 release Merges origin/main into DEV so the 1.20.0 DEV→main release PR (#2058) is conflict-free. All 4 conflicts (.deploy/mta.yaml, scripts/fetch-tutorials.ts, scripts/lib/content-cache.ts, test/unit/content-cache.test.ts) resolved to DEV: DEV carries the canonical content-cache fast path (#2039 + #2057 QA follow-up) that main only has via the #2044 cherry-pick; version stays 1.20.0. Resolved tree is byte-identical to origin/DEV — pure reconcile, no content change.
chore: sync main into DEV (reconcile for 1.20.0 release)
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.20.0 PROD deploy. 52 commits ahead of main.
Version
.deploy/mta.yaml1.19.0 → 1.20.0 (minor — feature release).Highlights since 1.19.0
/build/tagstag-taxonomy feed for CI validation (feat: add /build/tags tag-taxonomy feed for CI frontmatter validation #2051/fix(build/tags): emit mdFormat (category>value) slugs instead of display names #2053)Verification
/versionOK, content publishVerify OK: 715 slugs match, "Tag the Cat" confirmed live in the shipped island bundle,/whats-new/serving the new digest.<main>→<div>(a11y: duplicate-main + browse banner + figcaption contrast + concepts landmark #1989) stale-test assertions + the data-gated concept community-events check.Merge + deploy
origin/main(primary tree), blue-green; then the two PROD content-rebuild workflows.