{
  "schema": "price-lab-blueprint@1",
  "purpose": "Teaching and implementation design; not a ComfyUI UI/API workflow",
  "runnable": false,
  "missing_implementation": ["PriceLab bridge node package", "PriceLab worker API", "GRPO rollout evidence callback"],
  "base_model": "Qwen/Qwen2.5-0.5B-Instruct",
  "ports": {"comfyui": 8188, "worker_proposed": 8091, "model_service": 8088},
  "configs": {"sft": "sft.yaml", "grpo": "grpo.yaml", "reward": "rewards.py"},
  "routes": [
    {
      "id": "A",
      "title": "Prepare data and original baseline",
      "operations": ["prepare_data", "prepare_model", "eval"],
      "nodes": ["PriceLabExperiment", "PriceLabPrepareData", "PriceLabPrepareModel", "PriceLabSubmit", "PriceLabJobReadback", "PriceLabDataRead", "PriceLabArtifactRead", "PriceLabPreview"],
      "required_evidence": ["oracle checks", "disjoint partitions", "data and model hashes", "raw baseline completions"]
    },
    {
      "id": "B",
      "title": "Supervised fine-tuning",
      "operations": ["sft", "fuse", "eval"],
      "nodes": ["PriceLabSubmit", "PriceLabJobReadback", "PriceLabArtifactRead", "PriceLabPreview"],
      "training_parent_stage": "original",
      "training_parent_representation": "full",
      "smoke_iters": 5,
      "initial_formal_iters": 300,
      "required_evidence": ["finite updates", "changed parameters", "adapter", "fused model readback", "validation results"]
    },
    {
      "id": "C",
      "title": "Group-relative reinforcement learning",
      "operations": ["grpo", "fuse", "eval"],
      "nodes": ["PriceLabSubmit", "PriceLabJobReadback", "PriceLabArtifactRead", "PriceLabPreview"],
      "training_parent_stage": "sft",
      "training_parent_representation": "fused",
      "reference_stage": "sft",
      "smoke_iters": 5,
      "initial_formal_iters": 100,
      "group_size": 4,
      "required_evidence": ["SFT parent hash", "actual sampled completions", "rewards", "advantages", "parameter updates", "final model readback"]
    },
    {
      "id": "D",
      "title": "Serve and query the trained model",
      "operations": ["service_start", "service_readback", "price_request", "service_stop"],
      "nodes": ["PriceLabArtifactRead", "PriceLabServiceStart", "PriceLabServiceReadback", "PriceLabPriceRequest", "PriceLabServiceStop", "PriceLabPreview"],
      "training_dependency_in_query_graph": false,
      "service_artifact_representation": "fused",
      "required_evidence": ["final artifact identity", "actual healthy process", "raw model response", "strict amount grading", "saved request receipt"]
    }
  ],
  "job_states": ["accepted", "running", "succeeded", "failed", "cancelled"],
  "service_states": ["starting", "ready", "failed", "stopped"],
  "idempotency_fields": ["experiment_id", "operation", "request_id"],
  "display_output": "Readback, artifact read and price request nodes also return STRING JSON for PriceLabPreview",
  "separate_identifiers": ["prompt_id", "job_id", "service_id", "artifact_id"],
  "polling": "Separate Queue operations or a bounded UI polling component; never resubmit training to refresh status",
  "cancellation": "ComfyUI interrupt is separate from cancelling an external worker or stopping a model service"
}
