Problem
The simulation engine currently requires leads to pass through the SQL stage (via funnel progression mql → sal → sql → … → negotiation → closed_won) before they can convert. This means is_sql=False deterministically implies 0% conversion — a hard invariant that leaks outcome information into features.
This is documented as a known limitation in docs/v4/design.md:220 and tracked as a deferred engine fix in .agent-plan.md under "post-v1 list".
Root cause
In leadforge/simulation/engine.py, only leads at the negotiation stage are checked by ConversionHazard. Leads that never reach SQL can never reach negotiation, so they never convert.
Proposed fix
Add a rare "direct conversion" path: leads at pre-SQL stages (mql, sal) get a small daily probability of converting directly, bypassing the full funnel. This should be:
- Latent-score-modulated — higher latent → slightly higher direct conversion chance
- Much rarer than normal negotiation → closed_won path (e.g., 5% discount factor on the standard conversion hazard rate)
- Configurable — the discount factor should be a named constant, not a magic number
- The
is_sql field semantics should be unchanged — it still reflects whether the lead reached SQL
Acceptance criteria
- With enough leads, some non-SQL leads convert
- Non-SQL conversion rate is much lower than SQL conversion rate
- Determinism is preserved (same seed → same result)
- All existing tests pass (with appropriate updates to tests that assumed
is_sql=False → no conversion)
Labels
type: bugfix, layer: core, layer: simulation
Problem
The simulation engine currently requires leads to pass through the SQL stage (via funnel progression mql → sal → sql → … → negotiation → closed_won) before they can convert. This means
is_sql=Falsedeterministically implies 0% conversion — a hard invariant that leaks outcome information into features.This is documented as a known limitation in
docs/v4/design.md:220and tracked as a deferred engine fix in.agent-plan.mdunder "post-v1 list".Root cause
In
leadforge/simulation/engine.py, only leads at thenegotiationstage are checked byConversionHazard. Leads that never reach SQL can never reach negotiation, so they never convert.Proposed fix
Add a rare "direct conversion" path: leads at pre-SQL stages (
mql,sal) get a small daily probability of converting directly, bypassing the full funnel. This should be:is_sqlfield semantics should be unchanged — it still reflects whether the lead reached SQLAcceptance criteria
is_sql=False → no conversion)Labels
type: bugfix, layer: core, layer: simulation