← Files Marketing CouncilARCHIVED FILE
scripts/tactic_ranker.py
2.38 KB · Oct 2, 2026 · 00:31 UTC
#!/usr/bin/env python3
"""Rank marketing tactics with explicit weighted criteria."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
DEFAULT_WEIGHTS = {
"impact": 0.18,
"evidence": 0.15,
"strategic_fit": 0.15,
"audience_fit": 0.10,
"channel_fit": 0.08,
"measurement": 0.08,
"speed": 0.05,
"reversibility": 0.04,
"cost": 0.06,
"effort": 0.05,
"risk": 0.06,
}
POSITIVE = {"impact", "evidence", "strategic_fit", "audience_fit", "channel_fit", "measurement", "speed", "reversibility"}
NEGATIVE = {"cost", "effort", "risk"}
def _validate_score(name: str, value: float) -> float:
value = float(value)
if not 0 <= value <= 10:
raise ValueError(f"{name} must be between 0 and 10")
return value
def rank_tactics(tactics: list[dict], weights: dict[str, float] | None = None) -> list[dict]:
weights = dict(DEFAULT_WEIGHTS if weights is None else weights)
required = POSITIVE | NEGATIVE
if set(weights) != required:
raise ValueError(f"weights must contain exactly: {', '.join(sorted(required))}")
total_weight = sum(float(v) for v in weights.values())
if total_weight <= 0:
raise ValueError("weight total must be > 0")
ranked = []
for tactic in tactics:
name = str(tactic.get("name", "")).strip()
if not name:
raise ValueError("each tactic requires a non-empty name")
values = {k: _validate_score(k, tactic.get(k)) for k in required}
weighted = 0.0
for key in POSITIVE:
weighted += (values[key] / 10) * float(weights[key])
for key in NEGATIVE:
weighted += ((10 - values[key]) / 10) * float(weights[key])
score = 100 * weighted / total_weight
ranked.append({**tactic, "score": round(score, 2)})
return sorted(ranked, key=lambda x: (-x["score"], x["name"].lower()))
def main() -> None:
p = argparse.ArgumentParser(description="Rank tactics from a JSON file containing a list of scored tactics.")
p.add_argument("json_file", type=Path)
args = p.parse_args()
try:
tactics = json.loads(args.json_file.read_text(encoding="utf-8"))
result = rank_tactics(tactics)
except (ValueError, OSError, json.JSONDecodeError, TypeError) as exc:
p.error(str(exc))
print(json.dumps(result, indent=2, sort_keys=True))
if __name__ == "__main__":
main()
SHA-256: 1cb8907ede6a8bce93f2889f7c967c53b778aa00a4a6d7d3b393b43e25473992