DataTalksClub / DataTalksClub/website

Restore face8e4 formatting, typing, and focused content gates

Open
#261 11 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Product outcome

Restore the deterministic quality and focused-content gates on exact main face8e4808d65afbf0374d1ced7a88079950d663 without changing product behavior, copy, generated projections, or visual design. Malformed event/person normalization input must fail closed through the existing domain exception before any input is mutated; the accepted checked replay remains byte-for-byte semantically unchanged.

PM disposition: proceed as one bounded P0 gate-recovery issue. The four failures share one exact-main release envelope, have pinned non-overlapping changes, require no new product decision, and can be verified together. Splitting the runtime validator would add lifecycle overhead without an independently deliverable outcome. If engineering discovers that valid normalization behavior, the checked plan, a generated projection, or a public contract must change, stop and return that work to PM rather than expanding this issue.

Exact evidence and corrections to the raw intake

  • Base: face8e4808d65afbf0374d1ced7a88079950d663.
  • The readability file is templates/public/_prose_blocks.html, not the nonexistent templates/content/_prose_blocks.html; the nine compact conditional/element violations are at the exact-base lines 137–153.
  • The collection failure is not permission to weaken an exact class assertion. The exact-base archive partial emits literal archive-row and also selects archive-row for a dated row, while the focused contract expects one copy. Restore the canonical dated/undated outer classes and explicitly retain the accepted inner interactive-card interactive-lift classes.
  • Ruff remains locked at 0.16.1 and reports the six files listed below.
  • content/event_speaker_bio_normalization.py has four exact-base mypy errors and currently lets some unhashable/malformed projection shapes escape as builtin exceptions.

Scope

1. Restore the archive-row and collection-hub class contract

Allowed product source: templates/public/_archive_row.html only. Allowed focused tests: content/tests/test_archive_row.py and content/tests/test_collection_hub.py only.

  • A dated collection record renders the outer class serialization list-row archive-row record-row: one archive-row, no duplicate.
  • An undated record renders list-row archive-row archive-row-undated record-row: one base class plus the modifier.
  • The ordinary inner card remains exactly card archive-card stretched-card-link interactive-card interactive-lift.
  • The podcast inner card remains exactly card archive-card stretched-card-link podcast-card interactive-card interactive-lift.
  • Fix the partial's dated/undated class construction. Do not delete, rename, move, or weaken the accepted interaction classes to make a test pass.
  • Focused hub tests prove record counts over more than one page, page-one-only sitemap/canonical behavior, next/previous and numbered links, aria-current, invalid-page behavior, record ordering, and introduction-before-record semantics remain unchanged. Class assertions check the canonical outer row and the inner interaction contract independently.

This is a duplicate-token/source-contract correction only; CSS, interaction behavior, layout, and copy do not change.

2. Apply the locked formatter mechanically

Run Ruff 0.16.1 formatting on exactly these six pre-existing files for the formatter-only portion:

  • content/podcast_routes.py
  • content/public_data.py
  • content/tests/test_public_projection_builder.py
  • core/tests/test_interactive_surfaces.py
  • events/tests/test_prepare_registration_sources.py
  • playwright_tests/test_interactive_surfaces.py

Their changes must be the direct locked-formatter output only. Before/after Python ASTs are identical; no literal, assertion, marker, fixture, import behavior, route, data, timeout, retry, or test selection changes. Do not change Ruff configuration or version. Ordinary formatting of the separately edited normalization/test files is allowed, but it does not expand this six-file mechanical set.

3. Type and fail-close event speaker-bio replay

Allowed runtime source: content/event_speaker_bio_normalization.py. Add or extend focused coverage in content/tests/test_event_speaker_bio_normalization.py; a narrowly named new test module is allowed only if it avoids obscuring the existing replay contract.

  • Resolve all four exact-base mypy errors by real narrowing/validated typed structures. No cast, type: ignore, Any-only annotation, assertion deletion, or unchecked coercion is an acceptance substitute.
  • Preflight the entire checked plan and the complete supplied events and people collections before mutating either collection or nested provenance/blocks.
  • The top-level inputs must be lists; every visited event/person and every visited person block must be a mapping of the accepted shape before .get, membership, sorting, hashing, or copying.
  • Every consumed plan/source SHA, identity ID, slug, description, provenance field, block text, action, counter, boolean, conflict member, and digest has its explicit accepted scalar/container type before regex, set/dict lookup, comparison, JSON digest, or text normalization. bool is not accepted where an integer is required.
  • Event identity_id and event/person slug must be non-empty strings before they become dict/set keys. Duplicate, unknown, missing, mismatched, or incomplete event identities and required person targets fail closed. Non-target valid people remain untouched.
  • Null, boolean, numeric, list, dict, and other unhashable identifier/slug variants; non-mapping rows/blocks; invalid block lists/text; invalid description/provenance shapes; and malformed checked-plan scalar/container shapes raise EventSpeakerBioNormalizationError, never builtin TypeError, KeyError, AttributeError, ValueError, or an unbounded serializer error.
  • Failures expose one stable bounded allowlisted message category, do not interpolate the rejected value/source content, do not log source descriptions or PII, and leave both input collections deeply equal to their before-state.
  • Accepted first run and replay stay idempotent and preserve bridge/normalization provenance and the exact result:
{
    "events": 421,
    "described_events": 159,
    "speaker_bio_events": 155,
    "platform_boilerplate_blocks": 136,
    "people_changed": 17,
    "conflicts": 2,
    "internal_links_normalized": 154,
}

This boundary performs no network, database, provider, or durable-job side effect.

4. Refactor public prose source for readability only

Allowed product source: templates/public/_prose_blocks.html. Relevant tests are content/tests/test_public_template_source.py, content/tests/test_article_page.py, and content/tests/test_sponsor_article_charts.py; add only the smallest focused assertions needed.

Expand the compact conditional title/width/height attributes and inline figcaption/caption elements in the chart branches into readability-compliant Django-template source. Preserve:

  • the same figure/image/fallback node types, order, nesting, optionality, attributes, values, escaping, safe boundaries, lazy loading, decoding, alt/title/dimensions, captions, and visible text;
  • both the local-image chart branch and the Chart unavailable. fallback branch;
  • normalized rendered DOM, accessible names, link/image behavior, and visible copy. Only insignificant template-source/rendered inter-tag whitespace may differ.

No CSS, JavaScript, URL, metadata, content record, projection, chart asset, design-system, or product-copy change is allowed.

#253 boundary and dependencies

This issue is independently engineer-ready and does not wait for #253. It must not edit, regenerate, bless, roll back, or attest any checked JSON, content-source checkout, source pin, projection manifest/tree/hash, chart asset, generator, or terminology artifact. In particular, no file under content/public_projection/ or _docs/adoption/ changes here. If #253 later overlaps a formatter-only test file, rebase the mechanical formatting without importing #253 semantics.

No other product issue is a prerequisite. Work begins from the exact anchor above or a fresh current base that contains it; final tester evidence must identify the actual frozen base/candidate and cannot relabel the red anchor as green.

Acceptance criteria

  • Canonical dated/undated outer archive classes contain no duplicate token, accepted inner interactive-card interactive-lift classes remain exact, and focused multi-page collection/pagination semantics pass without assertion weakening.
  • Ruff 0.16.1 formatter output is clean; its pre-existing formatter-only diff is exactly the six named files and has identical Python ASTs.
  • The four normalization mypy errors are gone through validated narrowing, not casts/ignores/unchecked coercion.
  • Full preflight covers every consumed checked-plan/event/person/block shape before mutation; all malformed/hashability/type/coverage cases raise the stable domain error with no builtin exception, value disclosure, or partial mutation.
  • Valid first run and replay preserve the exact seven counters, 421-event/17-person outcome, checked provenance, deterministic ordering, and idempotence.
  • templates/public/_prose_blocks.html has no readability violation and both chart branches preserve normalized DOM, accessibility, attributes, copy, and visual output.
  • No generated projection/source/manifest/hash/asset/adoption-ledger file changes, and no #253 work is included.
  • Focused tests, locked format/lint/type checks, content invariants/source checks, migration drift check, and every graph-selected Django/browser/container gate terminate green on one frozen candidate. No retry, skip, xfail, quarantine, timeout extension, test removal/demotion, configuration bypass, or unchanged-red rerun counts as success.
  • Engineer and independent tester each publish source/diff/plan/run/report digests and terminal counts for the same candidate; tester uses a fresh environment and owns screenshot inspection.

Required focused scenarios

  1. Dated, undated, ordinary, and podcast archive rows; a multi-page collection with next/previous/number links, current page, invalid page, ordering, canonical/sitemap behavior, and no duplicate class token.
  2. Locked formatter check plus AST comparison for all six mechanical files.
  3. Checked-plan malformed top level, source scalar/SHA, count, event row, person row, conflict, digest, duplicate and unsorted variants; every failure is a domain error.
  4. Projection events with non-mapping row and identity/slug as missing, null, bool, number, list, and dict; duplicate/unknown/incomplete identity; description/provenance drift and wrong types.
  5. Projection people with non-mapping row; slug variants; missing required target; blocks missing/null/scalar; non-mapping block; non-string text; replace and append replay; valid non-target preserved.
  6. For a late failing person/plan shape, assert the entire event and people inputs equal a deep before-copy, proving validation occurred before the first mutation.
  7. Valid checked replay twice: exact counters above, provenance/digests, descriptions, people blocks, conflicts, and internal-link results remain deterministic.
  8. Render /blog/sponsor-datatalks-club.html (local-image charts) and /blog/datatalks-club-community-demographics.html (unavailable-chart fallback); assert optional title/dimensions/captions, alt/accessibility, visible text, no unexpected horizontal overflow, and no DOM/copy regression.

Verification and render disposition

Use only uv-backed commands/Make targets. At minimum run the exact focused Django modules named above, the affected Core/Events tests, the focused playwright_tests/test_interactive_surfaces.py, locked format-check, lint, typecheck, content source/invariant checks, migrations-check, and the versioned verification-plan / verification-run. Recompute the plan from the frozen diff; an unknown dependency selects the safer/full profile. A partial or timed-out suite is red.

  • Migrations: no model or migration change; new migration execution is not_applicable, while migration drift/check remains required.
  • Playwright: applicable because shared public template/class output changes; run the graph-selected tier plus the focused public chart/archive interactions.
  • Screenshots: applicable. The independent tester captures and inspects both named article routes at desktop 1440x900 and mobile 390x844, and representative dated/undated collection rows at those viewports. Record candidate SHA/diff digest, route, viewport, browser, screenshot digest, overflow/console/accessibility result, and explicit no-visual/no-copy comparison. JavaScript-disabled screenshots are not_applicable because no script behavior changes; if the final graph or implementation touches script behavior, enabled and disabled states become mandatory.
  • Large checked content / #253 attestation: not_applicable only when the final diff proves no projection/source/pin/manifest/hash/asset path changed; otherwise stop and return to PM.

Non-goals

  • No generated JSON, source pin, manifest/tree/hash, content asset, adoption-ledger, generator, or #253 recovery work.
  • No new normalization rule, checked-plan decision, counter, content rewrite, person merge, projection cardinality, or source/provider behavior.
  • No product copy, visual design, CSS, JavaScript, route, SEO, paginator, accessibility, or interaction change.
  • No broad typing/template/test refactor, dependency/tool/version/configuration change, or unrelated cleanup.
  • No weakening exact assertions, casts/ignores, retries, quarantine, xfail, skips, test deletion/demotion, gate bypass, timeout increase, or acceptance of partial evidence.

Lifecycle

Engineer implements in an isolated worktree, runs the focused and graph-selected gates, posts a Software Engineer Report, and freezes without commit/push. An independent tester recomputes the plan, tests malformed/no-partial-mutation and valid replay behavior, runs terminal gates, and inspects screenshots. PM then accepts or returns the candidate. Only the orchestrator may commit/merge/push after acceptance; use Refs #261 until final closure evidence is complete.

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 from the exact base and inspect the named sources: templates/public/_archive_row.html, templates/public/_prose_blocks.html, and content/event_speaker_bio_normalization.py, along with their focused tests. Run the specified focused Django, Core, Events, Playwright, format, lint, type, source, invariant, and migration checks using uv-backed commands. Done means the listed class, formatting, validation, replay, rendering, and no-generated-file-change criteria pass on one frozen candidate.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, playwright, python
Domain
backend, frontend, testing, tooling
Issue type
Refactor
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.