test(TEST-006): IPO pipeline end-to-end scenario test#102
Conversation
Every IPO stage has a focused suite, but each starts from a hand-built
fixture, so nothing proved the SEAMS between stages. This adds one scenario
walking a single company through the whole pipeline on REAL repository
functions and a real database, faking only true externals (SEBI HTTP, DNS,
clocks, the audit sink):
SEBI listing (faked fetch) -> run_scan_ipo_filings + real ingest_filings
-> issue + document rows (derived company identity asserted)
-> download_document + real download_document_file (fake session/resolver,
detail page -> iframe -> PDF)
-> submit_manual_extraction verified against the stage-2 cache
-> get_latest_ipo_ratios (hand-checkable EPS 20 / ROE 12.5 / P/E 12.1)
-> evaluate_issue -> "Recommended" + get_latest_recommendation.
The strongest lock is provenance continuity: the faked PDF's SHA-256 must
surface unchanged in the download result, the document row, the manual
revision, and the ratio analysis. The scenario is parametrized over BOTH
conftest engines (in-memory and file-backed production-pragma SQLite).
Test-only change; every existing suite passes unmodified.
Gates: 1,388 passed, coverage 88.13% (floor 87); pre-commit validate,
compileall, ruff, mypy (119 files), bandit, pip-audit all clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DoRmAmMu1997
left a comment
There was a problem hiding this comment.
Self-review (posted as COMMENT — the bot runs as the PR author and cannot APPROVE). Verdict: Approve.
Checks performed on the scenario:
- Real functions at every stage — the only doubles are true externals: the SEBI HTTP fetch (job
fetcher=), the downloader's HTTP session + DNS resolver (the downloader suite's own pattern), fixed clocks, and the audit sink.ingest_filings,download_document,download_document_file,submit_manual_extraction,get_latest_ipo_ratios,evaluate_issue, andget_latest_recommendationall run for real against a real schema. - Provenance chain is the core lock — the PDF digest is asserted at four hand-offs (download result → document row → manual revision → ratio analysis). This is the assertion that fails if any stage skips verification or silently re-reads different bytes; no per-stage suite can catch that class.
- Assertions are hand-computable — 10 crore PAT / 50 lakh shares → EPS 20; net worth 80 crore → ROE 12.5%; upper band 242 → P/E 12.1 (documented in the payload builder's beginner note). Decimal equality in Python is numeric, so quantization (20 vs 20.0000) cannot cause false failures.
- Derived identity asserted, not copied — the issue's company name/key come from
normalize_company_identityon the filing title, so the test locks the title-normalization seam into ingestion too. - Both engines — parametrized over the in-memory and file-backed (production-pragma) conftest factories via
request.getfixturevalue; both pass. The file-backed run also exercises real fsync/os.replace filesystem behavior in stage 2. - No cross-test imports — the HTTP doubles replicate the downloader suite's shape locally instead of importing from
tests/test_ipo_document_downloader.py; importing between test modules couples suites and breaks collection isolation. - Suites unmodified — no existing test touched; the IPO docstring-policy guard passes on the new module (every definition, including nested fakes, is documented).
Gates: 1,388 passed + 1 skipped, coverage 88.13% (floor 87); ruff/mypy(119)/bandit/pre-commit/compileall clean; pip-audit clean on retry after one transient PyPI read-timeout; constraints/pyproject diff vs main empty. Security review: no findings (test-only; the walk additionally exercises the SSRF gate and content-addressed verification end-to-end).
|
Codex review plan: I found no actionable standalone issue in TEST-006. I will rerun the two-engine IPO pipeline scenario and perform a test-only security review, then post a no-findings verdict. No branch change is planned unless the scenario exposes a regression. |
Completion verdictComplete — no findings. This is a completion comment, not an approval. No follow-up code changes were required. The IPO pipeline was rerun against both supported database engines; 2 end-to-end tests passed, and the review found no remaining actionable findings. |
Ticket scope (TEST-006)
Goal: lock the seams BETWEEN the IPO stages. Each stage already has a thorough isolated suite (
test_ipo_sebi_ingestion,test_scan_ipo_filings_job,test_ipo_document_downloader,test_ipo_manual_repository,test_ipo_ratio_engine,test_ipo_scorecard,test_ipo_verdict,test_ipo_repository) — but every one of them starts from a hand-built fixture, so a contract drift between two stages (e.g. ingestion persisting a URL shape the downloader rejects, or the extraction verifying against different bytes than the download wrote) would pass all of them and only fail in production.In scope
tests/test_ipo_pipeline_e2e.py, walking a single company end-to-end on real repository functions and a real database:run_scan_ipo_filingsjob loop + the realingest_filings, with only the SEBI HTTP fetch programmed. Asserts the issue's company identity is derived (title normalization →"Example Limited"/ key"example limited"), statusRHP_FILED, documentNOT_DOWNLOADED.download_documenttwo-transaction orchestration around the realdownload_document_file, with HTTP/DNS doubled (the downloader suite's fake-session pattern: detail page → iframe → PDF). Asserts the exact request sequence and the on-disk content-addressed bytes.submit_manual_extraction, verified against the stage-2 cache (not a hand-planted file).update_issue), thenget_latest_ipo_ratiosruns the pure engine on the latest revision. Spot values are hand-checkable: EPS 20, ROE 12.5%, P/E 12.1; EPS reconciliation not materially different.evaluate_issuewith the seven-factor input whosesource_documentsmust be URLs stage 1 actually registered →"Recommended",get_latest_recommendationround-trip.Out of scope (deliberate)
This is ticket 5 of a 10-ticket second improvement wave (TEST-007 #98, REF-003 #99, AI-006 #100, IPO-006 #101, TEST-006, PERF-002, DEPLOY-004, QUAL-006, QUAL-007, DOC-003), each shipped as its own PR off
main.Gates (all green, local, Python 3.13)
pytest -q --cov=backend --cov=screeners --cov=ui --cov-fail-under=87pre_commit validate-configcompileallruff checkmypy(119 files)banditpip_audit -r constraints.txtconstraints.txt/pyproject.tomldiff vs main: empty (as required).Review
/code-review: Approve — the scenario drives real functions at every stage (the only fakes are HTTP, DNS, clocks, and the audit sink); assertions are hand-computable; the fixture parametrization usesrequest.getfixturevalueso both engines run the identical walk./security-review: no findings (test-only diff; the scenario additionally exercises the SSRF gate, content-addressed verification, and actor normalization end-to-end).🤖 Generated with Claude Code