yannsay's picture
Deploy clean to build-small-hackathon org (32B Qwen, step-3 table)
aa1d0aa verified
Raw
History Blame Contribute Delete
2.86 kB
from __future__ import annotations
from pathlib import Path
import yaml
from core.runner import run_skill_script_raw
# Must be updated manually when catalog/*.yaml files change.
_CATALOG_DATE = "2026-06-13"
def assemble_spec_yaml(
session_dir: Path,
slug: str,
route: dict,
bind_results: dict,
indicator_defs: dict,
) -> Path:
"""Assemble analysis_spec_<slug>.yaml from bind loop results.
Returns the path to the written YAML file.
Never reads catalog/*.yaml directly — definitions come from indicator_defs (state).
"""
in_scope_sectors = route.get("sectors", [])
primary_sector = in_scope_sectors[0] if in_scope_sectors else "unknown"
indicators: dict = {}
for ind_id, bind in bind_results.items():
ind_def = indicator_defs.get(ind_id, {})
cluster = ind_def.get("cluster", primary_sector)
entry: dict = {
"label": ind_def.get("label", ind_id),
"dimension": f"sector::{cluster}",
"definition": ind_def.get("definition", ""),
"measurable": bind["measurable"],
"reasons": bind["reasons"],
"variables": bind["variables"],
# "Indicator name in the analysis" column. Code disposes: the result id is the
# catalog slug, not whatever the bind call put in result_ids (it leaks dataset
# variable names). The slug is the stable id the computed result carries.
"result_ids": [ind_id],
}
indicators[ind_id] = entry
spec = {
"dataset": slug,
"unit_of_analysis": "key_informant",
"n_total": 0,
"disaggregation": {
"by": "analyst-specified",
"groups": {},
"source_variables": [],
"trigger": "analyst-specified",
},
"step1_framework_route": {
"sector": primary_sector,
"pillar_2d": None,
"subpillar_2d": None,
"cross_cutting": None,
},
"step2_catalog_version": _CATALOG_DATE,
"indicators": indicators,
"uncovered_modules": [],
"gates": [],
}
out_path = session_dir / f"analysis_spec_{slug}.yaml"
out_path.write_text(
yaml.dump(spec, allow_unicode=True, sort_keys=False, default_flow_style=False)
)
return out_path
def render_spec_md(spec_yaml_path: Path, session_dir: Path) -> Path:
"""Render analysis_spec_<slug>.yaml to analysis_spec_<slug>.md.
Calls render_spec.py with no -o flag so it writes markdown to stdout.
Captures stdout and writes it to the session dir.
Returns the path to the written .md file.
"""
md_content = run_skill_script_raw("render_spec.py", [str(spec_yaml_path)])
md_path = session_dir / spec_yaml_path.with_suffix(".md").name
md_path.write_text(md_content)
return md_path