Skip to content

fix(content): serve-side underscore-slug 404 + document 3b/3c republishes (#2587) - #2637

Merged
jung-thomas merged 1 commit into
DEVfrom
worktree-issue-2587-serve-404
Oct 4, 2026
Merged

jung-thomas merged 1 commit into
DEVfrom
worktree-issue-2587-serve-404

Conversation

@jung-thomas

Copy link
Copy Markdown
Contributor

Closes #2587 (3a code fix). 3b/3c are PROD content-pipeline triggers that still need maintainer sign-off — commands + verification documented below, not executed.

3a — serve-time bug (fixed in this PR)

Root cause (confirmed): asymmetric slug validation. The publish path (packages/content/content-publish-session.js) stores slugs verbatim — underscores preserved — into ContentFiles/ContentCurrent. The serve path's VALID_SLUG = /^[a-z0-9][a-z0-9-]*$/ rejected underscores at serveHandler before any DB lookup, returning serveNotFound (404). So btp-integration-suite-creating_data_type-message_type and btp-integration-suite-editing_data_type-message_type were present in ACTIVE snapshot v281 with correct stepCount and healthy upstream, yet 404'd — the query was never reached.

Fix: widen the read-side gate to /^[a-z0-9][a-z0-9_-]*$/ (packages/content/content-store.js). First char still must be [a-z0-9] (leading _/uppercase still 400). Safe for topic/concept slugs: slugifyTopic() folds every non-[a-z0-9] run to a hyphen at generation, so they never arrive here with an underscore.

Tests: new underscore-slug serve cases (HTML + markdown alternate + mixed-case 301) in test/lib/content-store.test.js; malformed-slug test switched to a space (still 404). 69/69 pass across the three affected files (content-store, slug-utils, srv-qa/content-service).

Affected slugs (3a):

  • btp-integration-suite-creating_data_type-message_type
  • btp-integration-suite-editing_data_type-message_type

3b — backfill (never-republished; no content row in current snapshot) — NEEDS MAINTAINER

gh workflow run rebuild-content.yml --repo sap-tutorials/tutorials-ims --ref main -f slug=cp-kyma-api-mssql-golang
gh workflow run rebuild-content.yml --repo sap-tutorials/tutorials-ims --ref main -f slug=cp-kyma-mssql-deployment
gh workflow run rebuild-content.yml --repo sap-tutorials/tutorials-ims --ref main -f slug=cp-kyma-frontend-ui5-mssql
gh workflow run rebuild-content.yml --repo sap-tutorials/tutorials-ims --ref main -f slug=mobile-start-access-launchpad-site

3c — stale (fixed upstream, 1 step now) — NEEDS MAINTAINER

gh workflow run rebuild-content.yml --repo sap-tutorials/tutorials-ims --ref main -f slug=s4hc-abap-environment-create-custom-api

PROD verification plan (TEST THE ACTUAL THING)

After this fix is deployed to PROD (3a) and the 5 republishes complete (3b/3c), all 7 must return 200:

for s in \
  btp-integration-suite-creating_data_type-message_type \
  btp-integration-suite-editing_data_type-message_type \
  cp-kyma-api-mssql-golang \
  cp-kyma-mssql-deployment \
  cp-kyma-frontend-ui5-mssql \
  mobile-start-access-launchpad-site \
  s4hc-abap-environment-create-custom-api ; do
  printf '%s -> %s\n' "$s" "$(curl -s -o /dev/null -w '%{http_code}' "https://developers.sap.com/tutorials/$s.html")"
done

Baseline captured before fix: all 7 → 404; hyphen-only control slugs → 200; 3a slugs serve from X-Content-Source: db-current (Option B).

Deploy / sequencing notes

  • 3a flows through DEV per branching model (main is protected, no main-hotfix path).
  • 3b/3c rebuild-content.yml runs are PROD content mutations — run only with maintainer sign-off; must NOT be triggered from a workstation.
  • Deploy a fresh origin/main (never a feature branch) once this merges through to a release.

Serve path rejected tutorial slugs containing underscores before any DB
lookup. The publish path (content-publish-session.js) stores slugs
verbatim — underscores preserved — into ContentFiles/ContentCurrent, but
serveHandler's VALID_SLUG=/^[a-z0-9][a-z0-9-]*$/ failed the regex and
returned serveNotFound (404) for e.g.
btp-integration-suite-creating_data_type-message_type despite the slug
being present in ACTIVE snapshot v281 with correct stepCount.

Widen the read-side gate to /^[a-z0-9][a-z0-9_-]*$/ so read and write
agree. First char still must be [a-z0-9] (leading _/uppercase still 400).
Safe for topic/concept slugs: slugifyTopic() folds every non-[a-z0-9] run
to a hyphen at generation, so they never arrive here with an underscore.

Tests: new underscore-slug serve cases (HTML + markdown alternate +
mixed-case 301) in test/lib/content-store.test.js; malformed-slug test
switched to a space (still 404 under the new contract). Comments updated
in topic-slug.js, slug-utils.test.js, srv-qa/content-service.test.js.
69/69 across the three affected files.
@jung-thomas
jung-thomas merged commit 561b5c4 into DEV Oct 4, 2026
3 of 4 checks passed
@jung-thomas
jung-thomas deleted the worktree-issue-2587-serve-404 branch October 4, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant