#!/usr/bin/env python3
"""Plan T^GPT v0.8.2 confirmatory task count from independent planning-task effects.

Uses the observed SD of independent planning-task primary effects for a transparent
normal-approximation precision calculation and paired-effect power approximation.
This is a planning tool, not the confirmatory inferential engine.
"""
from __future__ import annotations
import argparse, json, math, statistics
from pathlib import Path

Z_975 = 1.959963984540054
Z_80 = 0.8416212335729143


def plan(data: dict) -> dict:
    effects = [float(x) for x in data["planning_task_effects"]]
    if len(effects) < 8:
        raise ValueError("at least 8 independent planning-task effects required; protocol target is >=12")
    sd = statistics.stdev(effects)
    half = float(data.get("target_half_width", 0.07))
    mde = float(data["minimum_relevant_effect"])
    alpha = float(data.get("alpha", 0.05)); power = float(data.get("power", 0.80))
    if abs(alpha - 0.05) > 1e-12 or abs(power - 0.80) > 1e-12:
        raise ValueError("v0.8.2 reference implementation currently supports alpha=.05 and power=.80")
    if half <= 0 or mde <= 0:
        raise ValueError("positive target_half_width and minimum_relevant_effect required")
    n_precision = math.ceil((Z_975 * sd / half) ** 2) if sd > 0 else 2
    n_power = math.ceil(((Z_975 + Z_80) * sd / mde) ** 2) if sd > 0 else 2
    minimum = int(data.get("minimum_tasks", 30)); cap = int(data.get("redesign_cap", 60))
    required = max(minimum, n_precision, n_power)
    return {
        "schema": "T_GPT_TASK_PLAN_RESULT_V0_8_2",
        "n_planning_tasks": len(effects),
        "planning_mean": statistics.mean(effects),
        "planning_sd": sd,
        "target_half_width": half,
        "minimum_relevant_effect": mde,
        "n_precision": n_precision,
        "n_power_approx": n_power,
        "minimum_tasks": minimum,
        "required_confirmation_tasks": required,
        "redesign_cap": cap,
        "decision": "GO_TO_FREEZE" if required <= cap else "REDESIGN_NO_GO",
        "guardrail": "Final task count is selected before confirmation from independent planning tasks; confirmation outcomes cannot alter it."
    }


def main():
    ap = argparse.ArgumentParser(); ap.add_argument("input", type=Path); ap.add_argument("-o", "--output", type=Path)
    a = ap.parse_args(); out = plan(json.loads(a.input.read_text(encoding="utf-8"))); payload = json.dumps(out, ensure_ascii=False, indent=2) + "\n"
    a.output.write_text(payload, encoding="utf-8") if a.output else print(payload, end="")


if __name__ == "__main__":
    main()
