Skip to content

Contributing

Hoda Rezvanjoo edited this page May 28, 2026 · 1 revision

Setup

git clone https://github.com/Hoda834/digital-budget-optimisation-engine.git
cd digital-budget-optimisation-engine
pip install -r requirements.txt
pip install pytest
pytest -q   # should print "141 passed"

Branch model

  • main is what Streamlit Cloud serves. Don't push directly.
  • Feature branches: feature/<short-description> or fix/<short-description>.
  • Open a PR against main. CI runs pytest -q on every push and PR.

Coding bar

  • Type hints required on public functions in modules/ and core/. from __future__ import annotations at the top of every module.
  • Comments explain why, not what. README and docs/ carry long-form explanation; keep code comments terse.
  • No new constants without a calibration entry. Every hand-tuned numeric literal needs a row in Calibration-Constants and docs/CALIBRATION.md.
  • Snapshots, not live state. Modules read from Module4Result-style immutable snapshots, never reach back into WizardState mid-solve.

Adding a platform

  1. Add the platform code to ALLOWED_PLATFORMS and PLATFORMS (wizard_state.py and module2.py).
  2. Add the display name to PLATFORM_NAMES in module7.py.
  3. Add KPI rows to KPI_CONFIG in core/kpi_config.py — one per (platform, goal, var).
  4. If the platform has a standard CSV export, add a parser block in core/csv_import.py with column mappings and composition rules.
  5. Add a smoke test in tests/smoke_test.py and an edge-case entry in tests/edge_cases.py if the platform has unusual behaviour.

Adding a constraint to the LP

  1. Add the constraint inside _solve_single_lp with a named LpConstraint.
  2. The name will appear automatically in binding_constraints and the diagnostics panel.
  3. If user-tunable, add the field to WizardState, surface it in app.py (Step 4 or "Refine and re-solve"), and snapshot it into Module4Result.

Adding a Module7Policy field

  1. Add a defaulted field to Module7Policy (the class is frozen=True, so callers explicitly pass a new instance).
  2. Reference it where a magic number would otherwise live.
  3. Add a row to Calibration-Constants documenting what changes when the value moves.

In scope / out of scope

In scope — new constraints, new platforms, better diagnostics, better forecast-band heuristics, more scenario archetypes (recession, growth, brand pivot), UI polish that doesn't change behaviour, tests (especially edge cases).

Out of scope — platform API connectors (this is a planner, not an operator), continuous learning / Bayesian recalibration (different product), campaign / ad-set / creative-level optimisation (downstream of the channel split), attribution and incrementality modelling (would need a different data foundation).

License

MIT. By contributing you agree your contributions are licensed under the same terms.

Clone this wiki locally