Used by ai_propose_clustering() during the multi-pass theme-
clustering algorithm in generate_themes_multipass(). Replaces (for the
v2 algorithm) the single-call .theme_decision_schema() which fused
structural and labeling decisions in one shot.
Details
Design contract honored by this schema (binding under C-tenets 3 and 5):
(a) NO name / description fields. Labeling happens in a
dedicated post-convergence pass (.theme_labeling_schema()).
The AI cannot leak name pressure into the structural decision.
(b) Per-cluster rationale field. The AI must justify EACH proposed
grouping in its own words, naming the codes it's grouping and why.
This is the "look at each code carefully" property without falling
into the earlier sequential-pairwise cascade. The AI still sees
ALL leaves at once – the "full picture" – but is forced to write a
justification per cluster.
(c) Closed two-valued verdict enum (continue or
converged). The AI either proposes a new partition that
groups the current leaves OR declares convergence. No hedging.
(d) cluster_assignments is nullable. When verdict is
converged the field is null. OpenAI strict mode
forbids conditional schemas (no oneOf), so the validation
contract is post-call: orchestrator checks that
continue + null or converged + non-null are rejected
and re-prompts.
{
"verdict": "continue" | "converged",
"cluster_assignments": [
{ "leaf_indices": [int, ...], "cluster_rationale": str }, ...
] | null,
"overall_rationale": str
}