PairwisePM / docs /technical-spec.md
brettleehari's picture
PairwisePM v0.1.0 — mechanical pairwise judge for GenAI product decisions (Spine and Leaf build)
3eb6857 verified
|
Raw History Blame Contribute Delete
6.19 kB

PairwisePM — Technical Specification (derives from spine/SPINE.md)

This document is the locked technical contract every Leaf builds against. It was settled in the working session of 2026-08-30 against the Noise / clinical-vs-mechanical research base (Meehl; Grove et al. 2000; Dawes 1979; Goldberg 1970; Bradley-Terry 1952; Kahneman/Sibony/Sunstein 2021). Where this document and the Spine conflict, the Spine wins.

1. Product shape

Two competing GenAI product ideas, A and B, entered on the same questionnaire, on one screen, in one sitting (occasion-noise cancellation: the pairwise delta cancels only noise shared by both scores, so both ideas MUST be scored together). A mode toggle selects the category:

  • 0→1 (search) — searching for product-market fit. Structure and consistency only; the UI carries a permanent banner: no predictive-accuracy claim.
  • 1→N (allocation) — roadmap allocation in an established product. The mechanical baseline with accuracy claims, earned over time via calibration.

Runtime is purely mechanical: numpy-only, no LLM, no API key, no network calls.

2. Factor schemas (editable config, one file per mode)

All factors z-scored against the accumulated log (seed distributions ship in config until the log grows). Each factor carries: scale, prior weight, sign, a written rationale, and a lever|fact tag (lever = changeable by working; fact = it is what it is). Evaluative inputs (strategic fit, brand) are captured and displayed but EXCLUDED from the mechanical score — labeled override inputs.

1→N mode

Factor Scale Prior w Tag
Impact on primary metric vs. named past feature, −2..+2 .25 lever
Capability feasibility eval/prototype pass rate, 0–4 .20 lever
Reach users affected/quarter (number) .15 fact
Unit economics value per use vs. inference cost, 0–4 .15 lever
Data flywheel usage→data→better feature, 0–4 .10 fact
Risk surface hallucination/compliance exposure, 0–4 reversed .05 lever
Effort person-weeks, reference-class adjusted −.10 lever

0→1 mode

Factor Scale Prior w Tag
Problem severity × frequency 0–4 .25 fact
Capability-trajectory exposure −2..+2 (stronger vs. absorbed as frontier models improve) .20 fact
Evidence of pull interviews/waitlist/pre-orders, 0–4 .20 lever
GenAI-necessity generative core vs. bolt-on, 0–4 .15 fact
Data/distribution advantage 0–4 .10 fact
Cost to test weeks to falsifiable prototype −.10 lever
Ceiling top-box flag unweighted —

The Ceiling flag never enters the score: when set, the verdict card routes the idea to human portfolio judgment ("high-ceiling outlier — portfolio decision, not averaged in").

Prior magnitudes for both tables are PENDING HUMAN SIGN-OFF — Decisions Leaf entries D1 and D2. Build with these defaults; they are config, not code.

3. The regression ladder (the model)

Level Model Trains on Active
M0 Prior-weight linear score, p = σ(wᵀd), d = z_A − z_B nothing always
M1 Ridge logistic Bradley-Terry on factor deltas, shrinkage centered on M0's prior weights (not zero) user's logged picks ≥ ~10 decisions
M2 Same regression vs. labeled outcomes outcome labels ≥ ~45 outcomes (future)
M3 Nonlinear ML hundreds of outcomes future, gated
  • Equal-weight ablation toggle (all |w| equal, signs kept) available as scientific control.
  • MAP regularization is mandatory from day one (two-fictitious-games / L2): pure MLE diverges on small or disconnected comparison graphs.
  • Intercept: constrained to zero for scoring (symmetry — swapping A and B must flip p exactly). ALSO fit unconstrained as a diagnostic: a significantly nonzero free intercept = measured presentation-order bias, surfaced in the audit report.
  • M1 vs. M0 weight divergence displayed as "what your revealed policy weighs vs. what you say you weigh."

4. Uncertainty & honesty rules

  • Bootstrap over factors → interval on the win probability. Interval straddling 50% → verdict renders as "too close to call — gather evidence", never a forced winner.
  • 0→1 mode: permanent structure-not-prediction banner.
  • Calibration: Brier score accumulates from decision 1; reliability curve when n permits.
  • ζ (Kendall's coefficient of consistency, from circular triads over the log) is the live per-judge noise meter; report it in the audit view.

5. Leverage panel (the actionable add-on)

For every comparison, on the linear logit L = wᵀd:

  1. Per-factor leverage: signed contribution w_j·d_j bar chart.
  2. Path to parity: for the loser, smallest single-factor change reaching 50/50 (and 60/40), reported in RAW units (required z-shift = L/w_j, converted via factor std).
  3. Lever/fact filter: parity paths proposed only through levers; if every path runs through facts → "loses on fundamentals — no working-harder path flips this."
  4. Fragility flag: if the winner's margin flips on a small plausible move of one factor → "margin rests on the estimate — re-estimate before committing."

6. Decision log

Local JSONL, downloaded/uploaded by the user (Space stores nothing server-side). Each record: timestamp, mode, both factor vectors (raw + z), evaluative inputs, pick, model outputs (M0 and M1 p, interval), override rationale if the user overrode, outcome slot (null until labeled later — schema ready for M2/M3). ζ and Brier are computed from the log; the log is the training set for M1.

7. Deliverable & deployment

  • pairwisepm/ pip-installable package (engine, log, config loader), app.py Gradio UI, tests/, HF Space files (README with YAML header, requirements.txt), pyproject.
  • Deployed as a Hugging Face Gradio Space; the same repo clones/installs locally.
  • README carries the epistemics: priors are a stated, editable policy, not fitted; 0→1 makes no accuracy claim; "the LLM's job was at build time — the runtime is weights and a bias term."