| Metadata | Value |
|---|---|
| Status | Completed |
| Version | 1.8.1 |
| Last Updated | 2026-02-19 |
| Author | Sangita Grantha Architect |
Consolidate all composition extraction logic (HTML and PDF) into the Python service. This eliminates the “Heuristic Split” between Kotlin and Python, centralizes domain expertise (regex, normalization), and simplifies the Kotlin backend into a “Pure Ingestor.”
Following the retrospective’s key lesson: Build one working slice first, then expand.
sangita-cli test extraction-e2e to run backend + DB + Python extractor checks without Playwright.PENDING -> PROCESSING -> DONE -> INGESTED) and DB assertions (extraction_queue, krithi_source_evidence).--keep-services, --skip-migrations, and --skip-extraction-start for rapid local diagnosis.src/html_extractor.py using BeautifulSoup4.
HtmlTextExtractor.kt.worker.py to poll for source_format = 'HTML' tasks.CanonicalExtraction object for a single Blogspot URL.ImportService.kt to allow submitting a PENDING HTML task to the extraction_queue instead of immediate scraping.DONE/INGESTED HTML extraction results are consumed to create/update Krithi records and link import records.submit URL -> queue task -> worker extraction -> ingest -> krithi_source_evidence -> import record linkage.raw_extraction::jsonb->'ragas'->0->>'name'), then rerun --max-rows 200 and confirm metadataMissingRows drops.
total_rows=200, keyed_rows=200, metadata_missing_rows=0.krithi_source_evidence (krithi_id, source_url).
database/migrations/35__add_krithi_source_evidence_krithi_source_url_index.sql.test_html_extractor.py, test_metadata_parser.py, and test_worker.py.
uv run python -m pytest tests/test_html_extractor.py tests/test_metadata_parser.py tests/test_worker.py -> 11 passed.structure_parser.py to output sectioned lyrics + metadata boundaries in CanonicalExtraction.
StructureParseResult (sections + metadata_boundaries) and canonical payload field metadataBoundaries.uv run python -m pytest tests/test_structure_parser.py tests/test_schema.py tests/test_worker.py -> 21 passed.KrithiStructureParser.kt into Python with fixture-backed parity checks.
structure_parser.py.tests/fixtures/structure_parser/kotlin_parity_multiscript.txttests/fixtures/structure_parser/kotlin_parity_tamil_headers.txtMEANING, NOTES, and known synonyms/variants before lyric segmentation.
metadataBoundaries offsets for downstream validation.latin, devanagari, tamil, telugu, kannada, malayalam).worker.py and cli.py now consume parser-emitted lyric_variants + metadata_boundaries directly for HTML/PDF/PDF-OCR flows.extraction-e2e scenarios with assertions for:
sangita-cli test extraction-e2e validation gate (validate_extraction_outcome) as hard failures on payload regressions.KrithiStructureParser.kt is no longer required for runtime extraction behavior.
extraction_queue -> Python worker -> ingestion) now uses Python parser contract exclusively.google-generativeai SDK for Gemini metadata enrichment (replacing GeminiApiClient.kt).BulkImportRepository.kt to atomically increment total_tasks for all job transitions (Fixing the 50% stall).KrithiStructureParser.kt, DeterministicWebScraper.kt, and GeminiApiClient.kt.compose.yaml to mount tools/krithi-extract-enrich-worker/src as a volume for instant logic updates.ragas array), with no unresolved accessor mismatch.sangita-cli test extraction-e2e to validate backend+worker queue integration before HTML migration slice.HTML queue format support (migration 31), implemented Python html_extractor.py, wired worker HTML path (HTML_JSOUP), and added test extraction-e2e --scenario blogspot-html using database/for_import/Dikshitar-Krithi-Test-20.csv.ragas[0].name accessor with fallback), added a metadata coverage regression assertion (metadataMissingRows must be 0), and added backend integration coverage for URL submit -> extraction ingestion -> source evidence -> import linkage (ExtractionResultProcessorTest).metadata_missing_rows=0).test_html_extractor.py, test_metadata_parser.py, test_worker.py: 11 passed).35__add_krithi_source_evidence_krithi_source_url_index.sql for (krithi_id, source_url) lookup performance and validated SQL execution shape (BEGIN/ROLLBACK parse check).sections plus deterministic metadata_boundaries, worker/CLI propagate these as metadataBoundaries in CanonicalExtraction, and regression tests confirm meaning/notes boundaries do not leak into lyric sections.google-generativeai) with fail-open behavior and extraction-method tagging (HTML_JSOUP_GEMINI) when metadata updates apply.identityCandidates).CanonicalExtraction Python schema + shared Kotlin DTO + canonical JSON schema) with identityCandidates and metadataEnrichment.sangita-cli test extraction-e2e to validate Phase 3 payload shape when signals are present.test_identity_candidates.py, test_gemini_enricher.py, worker/schema assertions for Phase 3 fields.uv run python -m pytest -> 97 passedcargo check --manifest-path tools/sangita-cli/Cargo.toml -> passed./gradlew :modules:backend:api:test --tests \"com.sangita.grantha.backend.api.services.ExtractionResultProcessorTest\" --tests \"com.sangita.grantha.backend.api.services.ImportServiceTest\" -> passedcargo run --manifest-path tools/sangita-cli/Cargo.toml -- test extraction-e2e --scenario blogspot-html --skip-migrations --timeout-seconds 240 --poll-interval-seconds 5 -> passed (minSections=11, minVariants=1)cargo run --manifest-path tools/sangita-cli/Cargo.toml -- test extraction-e2e --scenario pdf-smoke --skip-migrations --timeout-seconds 300 --poll-interval-seconds 5 -> passed (minSections=3, minVariants=1)cargo run --manifest-path tools/sangita-cli/Cargo.toml -- test extraction-e2e --scenario pdf-smoke --skip-migrations --timeout-seconds 300 --poll-interval-seconds 5 -> passed (minSections=3, minVariants=1)response_schema) for structured, robust metadata (including ragaMudra).429 ResourceExhausted errors in gemini_enricher.py.tests/test_schema_enrichment.py and E2E blogspot-html scenario.Phase 4 (Orchestration & Cleanup) partially completed — 50% stall fix applied, KrithiStructureParser deprecated. Full cleanup deferred.