| Metadata | Value |
|---|---|
| Status | Ready — unblocked, cleanup pending |
| Version | 1.1.0 |
| Last Updated | 2026-07-19 |
| Author | Sangeetha Grantha Team |
2026-07-19 — unblocked. This track was paused waiting for the legacy payloads to drain from the corpus. The TRACK-093 re-import has done that: all 1,238
imported_krithis.parsed_payloadrows are canonical (CanonicalExtractionDto), with zero legacyScrapedKrithiMetadata.SELECT CASE WHEN parsed_payload ? 'sections' THEN 'canonical' WHEN parsed_payload ? 'rawLyrics' OR parsed_payload ? 'scrapedAt' THEN 'legacy' ELSE 'other' END AS shape, COUNT(*) FROM imported_krithis GROUP BY 1; -- canonical | 1238The remaining work is the deletion cleanup: remove
ScrapedKrithiMetadataand the dual-format fallback branches now that nothing produces or reads the old shape. Re-run the query above immediately before deleting — the guarantee is “no legacy rows right now”, not a schema constraint, so a stray import between now and then would reintroduce one.
Converge on CanonicalExtractionDto as the single payload format for imported_krithis.parsed_payload and deprecate ScrapedKrithiMetadata. Eliminate the format schism that caused TRACK-094’s silent lyric persistence failure.
The import pipeline has two competing payload formats that evolved independently across different tracks:
| Format | Introduced | Producer | Location |
|---|---|---|---|
ScrapedKrithiMetadata |
TRACK-001 (original bulk import) | Kotlin WebScrapingService |
backend/api/.../services/WebScrapingService.kt |
CanonicalExtractionDto |
TRACK-041 (enhanced sourcing) | Python extraction worker | shared/domain/.../import/CanonicalExtractionDto.kt |
ScrapedKrithiMetadata — Kotlin scrapes HTML, parses sections, stores in parsed_payload, LyricVariantPersistenceService reads it at approval timeCanonicalExtractionDto as the “universal output contract” for all extraction adapters. Defined in shared domain module.ExtractionResultProcessor stores CanonicalExtractionDto in parsed_payload.LyricVariantPersistenceService was never updated to read CanonicalExtractionDto. The old format deserialization failed silently.imported_krithis.parsed_payload (8 files identified)ScrapedKrithiMetadata, ScrapedSectionDto, ScrapedLyricVariantDto, ScrapedTempleDetails as @Deprecated with ReplaceWith annotationsCanonicalExtractionDtoLyricVariantPersistenceService dual-format bridge (TRACK-094) handles both formats correctlyScrapeWorker no longer calls IWebScraper.scrapeKrithi() — extraction delegated to Python worker since TRACK-064IWebScraper parameter from ImportRoutes (was unused, kept only for backward-compat)IWebScraper parameter from ScrapeWorker constructorIWebScraper parameter from BulkImportWorkerServiceImpl constructorwebScrapingService from AppModule DI wiring for BulkImportWorkerServiceImplIWebScraper interface with @Deprecated annotationImportRoutesTest to remove mock IWebScraper usageIWebScraper, WebScrapingServiceImpl, DeterministicWebScraper, and DI binding —
already absent from the codebase (Phase 3’s removal went all the way; verified 2026-07-11).StructuralVotingEngine off ScrapedSectionDto (2026-07-11) — it now carries its own
VotedSection(type: RagaSectionDto, label). Landed on the domain RagaSectionDto enum rather
than CanonicalSectionType deliberately: voting scores on the richer technical-section set
(MUKTAYI/ETTUGADA/VILOMA/…) that CanonicalSectionType collapses to OTHER.
StructuralVotingProcessor builds VotedSection straight from canonical extractions; the
legacy LyricVariantPersistenceService fallback maps its ScrapedSectionDto at the call site.
No active code path outside the deprecated fallback references the scraper section DTO now.ScrapedKrithiMetadata fallback path from LyricVariantPersistenceService once no
legacy payloads remain in DB — blocked on the TRACK-093 re-import (the cutover that leaves
only canonical payloads). Until then the fallback + ImportService deity/temple parsing of
legacy payloads must stay.ScrapedKrithiMetadata and related DTOs (after the re-import).Decision: CanonicalExtractionDto is the single canonical format for extraction payloads going forward.
Rationale:
What NOT to do:
parsed_payload — always store structured CanonicalExtractionDtoScrapedKrithiMetadata — add them to CanonicalExtractionDto insteadCanonicalExtractionDtoLyricVariantPersistenceService to read both formats (bridge fix)Ref: application_documentation/10-implementations/track-096-payload-format-convergence.md