DataTalksClub / DataTalksClub/website

Restore .html canonical podcast detail URLs

Open
#162 13 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug content P0 seo testing
Dominant language
Python
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

Product outcome

Restore the established .html canonical for every podcast detail, including the two current exceptions S24E05 and S24E06, without changing podcast content or season-hub behavior. Current-base route and projection behavior must converge on one source-derived contract; generated projection files may not be hand-edited or hidden behind a runtime rewrite.

Normative authority and regression provenance

  • _docs/specs/02-url-link-seo-compatibility.md requires /podcast/<slug>.html for every podcast detail, with clean and trailing-slash slug aliases redirecting permanently in one hop while preserving the raw query.
  • #105/#119 establish deterministic public projection and podcast identity; #132 changes only the /podcast season-hub representation, not detail identities.
  • The prior #162 implementation, tester PASS, and PM acceptance remain the historical product contract. Merge c28d353551ff908498f450b2d03b127c97513feb implemented it.
  • bf82c20b760f97149b81f5745d3ba83211358078 later introduced the S24E05 exception. 9f0354402a3d75829f99d3f1545a1285281e27b2 introduced the equivalent S24E06 exception and generic stable-ID routes. Neither commit amended specification 02 or received an owner decision replacing the .html rule.
  • Exact current base face8e4808d65afbf0374d1ced7a88079950d663 has 205 podcast records: 203 .html paths and exactly two non-.html paths:
    • /podcast/s24e05/ai-adoption-in-enterprise-beyond-writing-code
    • /podcast/s24e06/how-to-build-ai-that-actually-ships-in-production

Historical acceptance therefore remains exact. This is a P0 compatibility/SEO regression, not a new route-design decision.

Scope

Canonical runtime and aliases
  • Make all 205 projected podcast public_path values exactly /podcast/<record-slug>.html. In particular:
    • /podcast/s24e05-ai-adoption-in-enterprise-beyond-writing-code.html
    • /podcast/s24e06-how-to-build-ai-that-actually-ships-in-production.html
  • Each .html final is a terminal GET/HEAD 200, has no Location, and emits one query-free production canonical, og:url, PodcastEpisode JSON-LD URL, and final breadcrumb URL matching that .html path. A query-bearing final remains 200, self-identifies with the query-free canonical, and is no-store.
  • Keep the established clean full-slug and trailing-slash full-slug aliases for every record as direct 301 redirects to its .html final, preserving the raw query byte-for-byte.
  • Preserve the two exact currently projected nested paths listed above as explicit compatibility aliases: each GET/HEAD redirects once with 301 to its matching .html final and preserves the raw query. Record them in the route migration/alias authority. This makes exactly 412 accepted podcast detail aliases: 410 established clean/slash aliases plus these two regression-era nested aliases.
  • Do not retain the generic /podcast/s<season>e<episode>, /podcast/s<season>e<episode>/<arbitrary-slug>, nested trailing-slash, or stale-cosmetic-slug resolver. Those unrecorded spellings return bounded 404 without Location or canonical metadata.
  • Finals and accepted aliases reject unsafe methods with 405, exact Allow: GET, HEAD, and no-store; malformed, ambiguous, duplicate-ID, and unknown records fail closed.
Source, projection, backlinks, and SEO
  • Remove the S24E05/S24E06 canonical exceptions from the shared route helper. The supported projection generator must derive both .html paths; runtime adapters must validate, not rewrite, generated identity.
  • Regenerate the complete public projection from the exact immutable pins accepted under #253. Two clean supported regenerations must be byte-identical to each other and to the checked result.
  • Update route-bearing generated outputs only from that complete regeneration, including podcasts.json, editorial_route_migration.json, manifest.json, Wiki records/graph/search, people relationships, review projection, and every derived source/artifact/tree digest that actually changes. No selected-file generation or hand-edited generated byte is accepted.
  • Every hub card, homepage/related link, Person relationship, Wiki citation/graph/search link, review link, feed, sitemap entry, canonical, Open Graph field, JSON-LD value, and breadcrumb must use the matching .html final. Source/editorial prose that merely contains a filename or fragment is not rewritten.
  • Preserve S24E06 source/artwork provenance and all unrelated generated semantics repaired under #253. This issue changes route identity only; it does not bless any face8e4 generated hash.

Dependency and integration order

This contract is fully groomed, but engineering is blocked while #253 remains in needs grooming and lacks its required green immutable content-source pin. This is a baseline/integration prerequisite, not an owner-decision gap and not permission to add needs grooming here.

After #253 records the repaired source SHA/tree/CI/attestation and a deterministic generator-ready base, the work must use one coordinated integration lane:

  1. apply this issue's route-helper/runtime/alias/test correction;
  2. let #253's complete two-pass regeneration consume that correction together with its source and generator repairs;
  3. freeze and independently verify the combined generated tree; and
  4. land in an order that never checks a runtime/projection mismatch.

#162 must not be implemented against stale face8e4 generated bytes, and #253 must not declare S24E06 route coherence while retaining the non-.html exception. The two issue reports must identify their exact owned semantic deltas; neither issue silently absorbs the other's acceptance.

Explicit non-goals

  • No change to /podcast season selection, ordering, pagination, controls, titles, query grammar, 24-season/205-episode inventory, transcripts, audio/player behavior, content, copy, people, or artwork.
  • No new season/episode canonical family and no generic public stable-ID resolver.
  • No change to Blog, Book, Person, Wiki detail, Event, course, or other route families.
  • No rollback or selective omission of the 16-commit lane associated with face8e4.
  • No hand-edited generated JSON/assets/provenance, partial regeneration, manifest/hash blessing, runtime projection rewriting, redirect chain, homepage fallback, test weakening, or unchanged-red workflow rerun.
  • No database model or migration, external content-repository mutation, provider action, Search Console action, production probe, deploy, or copy/visual redesign in this issue.

Acceptance criteria

  • The supported generator and runtime expose exactly 205 unique podcast finals, all matching /podcast/<record-slug>.html; S24E05 and S24E06 use the exact .html finals above.
  • The route migration contains exactly those 205 finals and exactly 412 explicit one-hop detail aliases: 410 clean/slash full-slug aliases plus the two exact nested compatibility aliases. There are no collisions, chains, guessed slash variants, generic ID aliases, or competing canonical 200s.
  • Every final passes the all-205 GET/HEAD/unsafe-method matrix and exact canonical/OG/PodcastEpisode JSON-LD/breadcrumb assertions. Every accepted alias passes the all-412 direct 301 GET/HEAD, raw-query preservation, and unsafe-method matrix.
  • The two nested compatibility aliases redirect directly to their .html finals for representative empty and byte-sensitive raw queries; their nested slash, ID-only, stale-slug, malformed, ambiguous, and unknown variants fail closed as specified.
  • /podcast and each valid season view retain the accepted season behavior and link only to .html details. The podcast sitemap is exactly clean /podcast plus the 205 .html finals and contains no alias, query, or nested detail URL.
  • A repository/projection census finds no S24E05/S24E06 nested path in a canonical/final/backlink/SEO scalar. The only permitted occurrences are the two explicit alias-source records and focused fixtures/assertions proving their redirects.
  • The #253-compliant complete regeneration runs twice from its accepted exact pins, produces identical full trees, matches all checked generated bytes, and accounts for every changed path/leaf and digest. Wiki/search route-field changes caused by this issue are classified as intentional .html backlink corrections; unrelated Wiki/search semantics and counts remain intact.
  • Focused route-helper, projection-builder, route-migration, public-data, podcast catalogue/stable-route, SEO, sitemap, review-projection, and Playwright tests cover both S24E05 and S24E06 plus the all-record matrices. Tests that currently endorse the exceptions are corrected rather than weakened.
  • A versioned verification plan selects fresh full quality, Django, Playwright, screenshot, and container evidence because shared generated projection, public routes, and rendered links change. All required jobs are terminal green on the exact frozen candidate; no face8e4 failure evidence is reused as success.

Browser and independent tester scenarios

  1. At 1440px and 390px, with JavaScript enabled and disabled where the harness supports it, open both S24E05 and S24E06 .html finals directly. Verify terminal 200, correct address/canonical/OG/JSON-LD/breadcrumb, readable content, working media surface, no debug/error page, and no horizontal overflow.
  2. At both widths, open each exact nested compatibility alias with ?utm_source=oncall%2Btest&x=a%2Fb&blank=. Verify one permanent hop preserves the raw query and lands on the correct .html final; inspect the final render.
  3. Open /podcast?season=24, activate the visible S24E05 and S24E06 cards, and verify each link goes directly to its .html final without a browser redirect. Confirm season controls and episode ordering remain unchanged.
  4. Exercise representative Person and Wiki backlinks for both episodes and confirm direct .html destinations. Verify nested slash, ID-only, stale-slug, malformed, and unknown paths show the safe 404 rather than a detail, hub, or redirect.

The independent tester captures and inspects desktop/mobile screenshots for the season-24 hub and both final detail pages. Screenshots are applicable because public href/address behavior and shared generated render inputs change, even though visible copy/CSS is unchanged.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with _docs/specs/02-url-link-seo-compatibility.md and confirm the #253 prerequisite before inspecting the shared route helper, supported projection generator, runtime adapters, route migration, and named generated outputs. Verify the all-record route, alias, SEO, backlink, and unsafe-method tests for S24E05 and S24E06. Done means a complete deterministic regeneration produces 205 .html finals and exactly 412 accepted aliases with all required evidence green.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend, testing, web-dev
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.