"""Step 12 smoke — run_project composes the slice end-to-end on an injected FakeChatClient. Returns a ValidatedProposal with a populated first-class ProvenanceStamp. Pattern: tests/test_smoke.py. """ from spikes._harness import FakeChatClient from portfolio_optimiser.provenance import ProvenanceStamp from portfolio_optimiser.run import run_project from portfolio_optimiser.validator import ValidatedProposal _VALID = ( '{"project_id":"FV42-GSV-E1","measure":"Reduce scope",' '"affected_items":[{"code":"05.2","quantity":4300,"unit_cost":215},' '{"code":"03.1","quantity":1800,"unit_cost":310}],"claimed_saving_nok":200000}' ) async def test_run_project_smoke(tmp_path) -> None: docs = tmp_path / "docs" docs.mkdir() (docs / "cost.txt").write_text( "Asphalt Ab11 unit rate renegotiation reduced the paving cost on the school stretch.", encoding="utf-8", ) def factory(role: str) -> FakeChatClient: return FakeChatClient(default_reply=_VALID) result = await run_project( "FV42-GSV-E1", "local", docs_dir=str(docs), verdict_input={"decision": "approved", "rationale": "feasible within range"}, client_factory=factory, ) assert isinstance(result.outcome, ValidatedProposal) assert isinstance(result.provenance, ProvenanceStamp) assert len(result.provenance.citations) >= 1