6.5 KiB
Context
This change addresses unresolved regressions introduced by recent UX and content pipeline updates. The affected areas cross frontend interaction patterns (frontend/index.html), policy content delivery (backend/main.py), translation generation (backend/news_service.py), and admin image maintenance operations (backend/cli.py). Current behavior still allows low-quality translations and repeated or weakly related refetched images, and policy links still rely on full-page navigation.
Key constraints:
- Maintain existing OpenSpec capability contracts where possible and ship mostly as requirement deltas.
- Preserve permalink identity for machine/admin targeting, while removing redundant user-facing permalink chrome on hero.
- Keep deterministic fallback behavior (AI-themed image fallback and English fallback for failed translations).
Goals / Non-Goals
Goals:
- Deliver modal-based Terms and Attribution access with keyboard-safe behavior.
- Remove visible hero permalink affordance while preserving internal permalink targeting.
- Improve Tamil/Malayalam hero readability on desktop and mobile.
- Switch copy and back-to-top controls to icon-first interaction while preserving accessibility labels.
- Add translation quality validation gates (wrong-language/gibberish rejection and deterministic fallback).
- Extend refetch-images to support permalink targeting and enforce alternative relevant image selection (non-repeat, relevance/safety filters, AI fallback when uncertain).
Non-Goals:
- Replacing the existing rendering framework or routing model.
- Introducing new external image providers in this change.
- Reworking full article ingestion architecture beyond targeted translation/image guardrails.
Decisions
Decision 1: Policy disclosure moves to modal-first UI with deep-link-safe state
Use in-page modals for Terms and Attribution content while supporting deterministic open/close state from URL params or equivalent state synchronization.
Alternatives considered:
- Keep route pages only: rejected due to UX friction and context switch from main feed.
- Embed truncated inline footer text: rejected due to disclosure readability and legal clarity risks.
Decision 2: Hero permalink identity remains internal, not a primary visual affordance
Retain permalink generation/parsing helpers for deep links and admin targeting, but remove visible hero permalink action from hero chrome.
Alternatives considered:
- Remove permalink behavior entirely: rejected because admin targeting and deep-link tooling need stable identifiers.
- Keep visible permalink: rejected because current hero action density and readability are degraded.
Decision 3: Locale-aware hero readability profile for Tamil/Malayalam
Apply stronger readability guardrails for non-English hero text: increased contrast treatment, safer line-wrapping, language-specific typography tuning.
Alternatives considered:
- Single style for all languages: rejected; longer glyph clusters and script density degrade legibility.
- Separate locale-specific templates: rejected as too heavy for this stabilization change.
Decision 4: Icon-only controls must remain explicitly accessible
Use icon-based copy and back-to-top controls with accessible names, keyboard operation, and stable tap targets.
Alternatives considered:
- Text-only controls: rejected by updated UX requirement.
- Icon-only without explicit labels: rejected due to WCAG and discoverability concerns.
Decision 5: Translation quality gate before persistence/serving
Add post-generation validation for expected language/script sanity and basic gibberish detection. If validation fails, mark translation unavailable and serve deterministic English fallback.
Alternatives considered:
- Blindly accept model output: rejected due to current wrong-language/gibberish incidents.
- Human moderation for all translations: rejected for runtime latency and operational overhead.
Decision 6: Refetch image selection becomes candidate-based and non-repeat
For refetch operations, generate contextual query candidates, filter against relevance/safety constraints, reject current/previously used image matches for the same article, and fall back to AI-themed image when confidence is low or candidates are exhausted.
Alternatives considered:
- First-provider-first-image approach: rejected because it often repeats or returns weakly related imagery.
- Hard blocklist only: rejected; insufficient for relevance and dedupe guarantees.
Decision 7: Admin refetch supports permalink-targeted execution
Extend admin command contract to accept a permalink input, resolve to article identity, and run the same queue/refetch pipeline with targeted scope.
Alternatives considered:
- Keep limit-based batch-only refetch: rejected; operators need deterministic single-article correction path.
- Add separate ad hoc script: rejected due to fragmented operational surface.
Risks / Trade-offs
- [Risk] Modal policy flow may regress keyboard/focus behavior -> Mitigation: explicit focus trap, escape-close, and focus-return requirements.
- [Risk] Translation validation may over-reject valid short outputs -> Mitigation: bounded heuristic thresholds plus deterministic English fallback and logging for tuning.
- [Risk] Stronger image filtering can reduce image diversity -> Mitigation: multi-candidate ranking and fallback to AI-themed image instead of unrelated imagery.
- [Risk] Permalink-targeted admin flow may fail on malformed or stale links -> Mitigation: strict permalink parser and clear operator error summaries.
Migration Plan
- Introduce modal policy behavior and hero/readability/icon control updates in frontend.
- Add translation quality gate logic and fallback outcomes in backend translation path.
- Extend image refetch pipeline with candidate ranking, dedupe, relevance/safety filters, and fallback.
- Add permalink-targeted admin refetch argument and resolution path.
- Validate through existing/manual verification paths and update OpenSpec tasks.
Rollback:
- Revert p16 frontend modal/icon/readability changes.
- Revert translation gate checks to prior translation acceptance path.
- Revert permalink-targeted and dedupe-aware refetch logic to prior batch refetch behavior.
Open Questions
- Should policy modals update canonical URL state (
?modal=terms) for shareable deep links, or stay ephemeral-only? - What minimum confidence/sanity threshold should trigger translation rejection for short headlines?
- Should image dedupe history persist only per article current/previous image, or maintain wider history window?