{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://github.com/{owner}/multi-agent-pipeline/pipeline/schemas/analysis-spec.schema.json",
  "version": "1.3.0",
  "title": "Multi-Agent Pipeline - /multi-agent:analysis spec output (v3 template)",
  "description": "Contract for the feature-spec analysis document generated by /multi-agent:analysis. Platform-agnostic concept layer + Pass B per-platform render with repo-driven conventions. 23 sections in Full mode; 8 of them in Lite mode. Sections may be absent - omission is the policy when no evidence exists.",
  "type": "object",
  "additionalProperties": false,
  "required": ["featureName", "language", "platforms", "repos", "evidence", "sections"],
  "properties": {
    "featureName": {
      "type": "string",
      "minLength": 1,
      "description": "Free-text feature name supplied by the user (e.g. 'FlightStatus', 'PaymentEndpoint')."
    },
    "phase": {
      "type": "string",
      "enum": [
        "intake",
        "fetching",
        "collecting_repo_evidence",
        "extracting_conventions",
        "synthesizing_pass_a",
        "awaiting_pass_b_approval",
        "rendering_pass_b",
        "drafting",
        "awaiting_output_decision",
        "dispatching",
        "reporting",
        "done",
        "cancelled_at_pass_b_preview"
      ],
      "description": "Resume marker. Set by the orchestrator after each phase boundary."
    },
    "mode": {
      "type": "string",
      "enum": ["full", "lite"],
      "default": "full",
      "description": "Output mode. Full renders 23 sections. Lite renders 1, 2, 4, 9, 13, 14, 21 + optional 23. Auto-resolved when both --lite and --full flags are absent."
    },
    "liteModeAuto": {
      "type": "boolean",
      "default": false,
      "description": "True when Phase 1c detected small-feature signals (spec < 100 lines AND figma frames <= 1 AND repo direct-match >= 8). User flags override this."
    },
    "templateVersion": {
      "type": "string",
      "enum": ["v2", "v3"],
      "default": "v3",
      "description": "Template version emitted. v3 is the platform-agnostic + Pass B render template (Locked 22)."
    },
    "profile": {
      "type": "string",
      "enum": ["global", "corporate"],
      "default": "global",
      "description": "Analysis profile chosen at Phase 0 Step 1b (Locked 32). 'global' renders analysis-template.md (23-section development handoff); 'corporate' renders analysis-template-corporate.md (IG/UC/FG requirements document). Both read the same evidence; only the projection differs."
    },
    "options": {
      "type": "object",
      "additionalProperties": false,
      "description": "Coverage opt-ins captured at Phase 0 Step 5a. Absent = defaults (no UI tests, basic accessibility).",
      "properties": {
        "uiTests": {
          "type": "boolean",
          "default": false,
          "description": "When true, Section 15.6 renders UI test scenarios (XCUITest / Compose UI test)."
        },
        "a11yDepth": {
          "type": "string",
          "enum": ["basic", "full"],
          "default": "basic",
          "description": "basic = Section 16.1 checklist only; full = also render the 16.2 VoiceOver/TalkBack walkthrough."
        }
      }
    },
    "evidenceDigest": {
      "type": ["string", "null"],
      "pattern": "^sha256:[0-9a-f]{64}$",
      "description": "Cache key for Phase 1b and 1c outputs. Cache hit skips both phases. TTL 24h."
    },
    "conventionOverrides": {
      "type": "object",
      "description": "User overrides applied at Phase 2a Pass B preview. Keyed by repo name, then field key. Pass B reads overrides before defaults.",
      "additionalProperties": {
        "type": "object",
        "additionalProperties": {
          "type": "object",
          "additionalProperties": false,
          "required": ["pattern"],
          "properties": {
            "pattern": { "type": "string" },
            "reason": { "type": ["string", "null"] }
          }
        }
      }
    },
    "language": {
      "type": "string",
      "enum": ["tr", "en"],
      "description": "Output language, resolved from prefs.global.outputLanguage."
    },
    "platforms": {
      "type": "array",
      "minItems": 1,
      "items": { "type": "string", "enum": ["ios", "android", "backend", "frontend"] },
      "description": "Platforms selected in Phase 0 step 3 (multi-select)."
    },
    "repos": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["platform", "name", "canPush"],
        "properties": {
          "platform": { "type": "string", "enum": ["ios", "android", "backend", "frontend"] },
          "name": { "type": "string", "minLength": 1 },
          "cloneUrl": { "type": ["string", "null"] },
          "canPush": { "type": "boolean" }
        }
      },
      "description": "Repos selected in Phase 0 step 4 (multi-select, per-platform). canPush gates write-back."
    },
    "evidence": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "figma": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["url"],
            "properties": {
              "url": { "type": "string", "format": "uri" },
              "fileKey": { "type": ["string", "null"] },
              "nodeId": { "type": ["string", "null"] },
              "screenshotUrl": {
                "type": ["string", "null"],
                "description": "Local PNG path or signed render URL for this node."
              },
              "tier": {
                "type": ["integer", "null"],
                "enum": [1, 2, 3, null],
                "description": "Figma access tier used to capture this record (mirrors state.figmaAccess.tier)."
              },
              "frames": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "name": { "type": "string" },
                    "variant": { "type": ["string", "null"] },
                    "thumbnailUrl": { "type": ["string", "null"] }
                  }
                }
              },
              "components": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "name": { "type": "string" },
                    "variants": { "type": "array", "items": { "type": "string" } },
                    "codeConnectMapped": { "type": "boolean" },
                    "repoPath": { "type": ["string", "null"] }
                  }
                }
              },
              "codeConnectSnippets": {
                "type": "array",
                "description": "Verbatim CodeConnectSnippet blocks captured on Tier 1 (component name + modifier chain).",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "nodeId": { "type": ["string", "null"] },
                    "component": { "type": "string" },
                    "snippet": { "type": ["string", "null"] }
                  }
                }
              },
              "tokens": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "name": { "type": "string" },
                    "value": { "type": ["string", "null"] }
                  }
                }
              },
              "textLayers": {
                "type": "array",
                "description": "Visible text-layer content. Treated as placeholder copy when an annotation exists for the same node (annotation wins).",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "nodeId": { "type": ["string", "null"] },
                    "name": { "type": ["string", "null"] },
                    "text": { "type": "string" }
                  }
                }
              },
              "annotations": {
                "type": "array",
                "description": "Dev Mode annotations captured as authoritative copy ground truth (Phase 1 annotation ingestion). Empty unless annotations.enabled in the project figma-config.",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": ["nodeId", "mode"],
                  "properties": {
                    "nodeId": { "type": "string" },
                    "name": { "type": ["string", "null"] },
                    "designText": {
                      "type": ["string", "null"],
                      "description": "The visible-layer text at this node (often a placeholder)."
                    },
                    "raw": {
                      "type": ["string", "null"],
                      "description": "The raw annotation label/labelMarkdown before parsing."
                    },
                    "parsed": {
                      "type": "object",
                      "description": "Parsed copy keyed by language code (lowercased), e.g. { tr, en }.",
                      "additionalProperties": { "type": "string" }
                    },
                    "mode": {
                      "type": "string",
                      "enum": ["prefixed", "two-line", "single", "empty"]
                    }
                  }
                }
              }
            }
          }
        },
        "swagger": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["url"],
            "properties": {
              "url": { "type": "string", "format": "uri" },
              "endpoints": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": ["method", "path"],
                  "properties": {
                    "method": {
                      "type": "string",
                      "enum": ["GET", "POST", "PUT", "PATCH", "DELETE"]
                    },
                    "path": { "type": "string" },
                    "summary": { "type": ["string", "null"] },
                    "auth": { "type": ["string", "null"] },
                    "request": { "type": ["object", "null"] },
                    "responses": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": ["code"],
                        "properties": {
                          "code": { "type": "integer" },
                          "body": { "type": ["object", "string", "null"] },
                          "userFacing": { "type": ["string", "null"] },
                          "action": { "type": ["string", "null"] }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "confluence": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["url"],
            "properties": {
              "url": { "type": "string", "format": "uri" },
              "pageId": { "type": ["string", "null"] },
              "title": { "type": ["string", "null"] },
              "embeddedApiTable": { "type": "boolean", "default": false }
            }
          }
        },
        "jira": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["id"],
            "properties": {
              "id": { "type": "string", "pattern": "^[A-Z]+-[0-9]+$" },
              "summary": { "type": ["string", "null"] }
            }
          }
        },
        "repo": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["repoName"],
            "properties": {
              "repoName": { "type": "string" },
              "localizationKeys": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "key": { "type": "string" },
                    "tr": { "type": ["string", "null"] },
                    "en": { "type": ["string", "null"] }
                  }
                }
              },
              "deeplinkHandlers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "scheme": { "type": "string" },
                    "path": { "type": "string" },
                    "handler": { "type": "string" }
                  }
                }
              },
              "pushHandlers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "event": { "type": "string" },
                    "handler": { "type": "string" }
                  }
                }
              },
              "codeConnectFiles": {
                "type": "array",
                "items": { "type": "string" }
              }
            }
          }
        },
        "standards": {
          "type": "array",
          "description": "Binding standards / coding documentation sources (Q5).",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["source"],
            "properties": {
              "source": { "type": "string", "description": "URL or local path" },
              "kind": {
                "type": "string",
                "enum": ["local-file", "wiki", "standards-confluence", "generic-doc", "document"]
              },
              "binding": { "type": "boolean", "default": true },
              "title": { "type": ["string", "null"] }
            }
          }
        },
        "firebase": {
          "type": "array",
          "description": "Firebase Analytics event sources (Q6).",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["kind"],
            "properties": {
              "kind": {
                "type": "string",
                "enum": ["names", "schema", "console"],
                "description": "Sub-type: names (comma list), schema (local JSON), console (reference-only URL)."
              },
              "source": {
                "type": ["string", "null"],
                "description": "Original input string (path, URL, or comma list)."
              },
              "events": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": ["name"],
                  "properties": {
                    "name": { "type": "string" },
                    "trigger": { "type": ["string", "null"] },
                    "params": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "name": { "type": "string" },
                          "type": { "type": ["string", "null"] },
                          "required": { "type": "boolean", "default": false }
                        }
                      }
                    },
                    "platformsEmitting": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": ["ios", "android", "backend", "frontend"]
                      }
                    },
                    "citation": { "type": ["string", "null"] }
                  }
                }
              }
            }
          }
        },
        "repoEvidence": {
          "type": "object",
          "description": "Phase 1b deep-scan result keyed by repo name. Each value holds the 13-bucket catalogue.",
          "additionalProperties": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "buckets": {
                "type": "object",
                "additionalProperties": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": ["name", "file", "tag"],
                    "properties": {
                      "name": { "type": "string" },
                      "file": { "type": "string" },
                      "line": { "type": ["integer", "null"] },
                      "tag": {
                        "type": "string",
                        "enum": ["direct-match", "same-domain", "cross-cutting"]
                      }
                    }
                  }
                }
              },
              "fetchWarnings": {
                "type": "array",
                "items": { "type": "string" }
              }
            }
          }
        },
        "documents": {
          "type": "array",
          "description": "Attached specification documents fetched by lib/fetch-document.sh (.docx / .pdf / .md / .txt). A document whose text could not be extracted stays in this list with fetched=false so Section 21 still cites it; dropping it would make the analysis read as if the file was never supplied.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["path", "format", "fetched"],
            "properties": {
              "path": { "type": "string", "description": "Local path or source URL as supplied." },
              "format": { "type": "string", "enum": ["docx", "pdf", "md", "txt"] },
              "fetched": {
                "type": "boolean",
                "description": "False when the converter was unavailable (no pdftotext on the machine) - the citation survives, the body text does not."
              },
              "title": { "type": "string" },
              "text": {
                "type": "string",
                "description": "Extracted plain text. Absent when fetched is false."
              },
              "binding": {
                "type": "boolean",
                "default": false,
                "description": "True when the user marked it a binding standard (Q5); the entry is mirrored into standards[]."
              }
            }
          }
        },
        "outside": {
          "type": "array",
          "description": "Phase 1d evidence tier from ai-analyst-toolkit: GitHub issues / PRs / releases and package-registry facts. Each entry has a citable identity, so it may feed any section (Locked 3).",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["source", "citation", "claim"],
            "properties": {
              "source": { "type": "string", "enum": ["github", "registry"] },
              "citation": {
                "type": "string",
                "description": "GitHub:<owner>/<repo>#<n> or Release:<pkg>@<version>."
              },
              "claim": { "type": "string" },
              "url": { "type": "string" }
            }
          }
        },
        "signals": {
          "type": "array",
          "description": "Phase 1d signal tier: Stack Overflow, Hacker News, and opt-in Reddit / X. Advisory only - Section 20 Risks is the ONLY section allowed to carry these, and they are excluded from the evidence digest because they change by the hour.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["source", "claim", "url"],
            "properties": {
              "source": {
                "type": "string",
                "enum": ["stackoverflow", "hackernews", "reddit", "x"]
              },
              "claim": { "type": "string" },
              "url": { "type": "string" },
              "reportCount": {
                "type": "integer",
                "minimum": 1,
                "description": "How many distinct reports back the claim. One report and a hundred are different facts, and only the second one changes a priority."
              },
              "observedAt": { "type": "string", "description": "ISO date the signal was read." }
            }
          }
        },
        "freeText": {
          "type": "array",
          "description": "User statements made in conversation that no fetched source carries, recorded so Section 21 can cite the decisions they settled (Locked 34).",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["text"],
            "properties": {
              "label": { "type": "string" },
              "text": { "type": "string" },
              "role": { "type": "string" }
            }
          }
        },
        "fetchErrors": {
          "type": "array",
          "description": "Phase 1 access failures (401/403/login-redirect). Surfaced as warnings, not blockers.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["url", "type", "reason"],
            "properties": {
              "url": { "type": "string" },
              "type": { "type": "string" },
              "reason": { "type": "string" }
            }
          }
        },
        "conventions": {
          "type": "object",
          "description": "Phase 1c convention extraction result keyed by repo name. Each value holds 7 pattern groups (12 fields total).",
          "additionalProperties": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "additionalProperties": false,
              "required": ["pattern", "confidence"],
              "properties": {
                "pattern": { "type": "string" },
                "example": { "type": ["string", "null"] },
                "confidence": {
                  "type": "string",
                  "enum": ["high", "medium", "low", "none"]
                },
                "evidenceFiles": {
                  "type": "array",
                  "items": { "type": "string" }
                },
                "alternativeCandidates": {
                  "type": "array",
                  "items": { "type": "string" }
                },
                "fetchWarning": { "type": ["string", "null"] }
              }
            }
          }
        },
        "conventionRisks": {
          "type": "array",
          "description": "Auto-populated from Phase 1c when convention confidence is low or none. Section 20 Risks reads this list and emits one open question per entry.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["repo", "field", "confidence", "fallback", "question"],
            "properties": {
              "repo": { "type": "string" },
              "field": { "type": "string" },
              "confidence": { "type": "string", "enum": ["low", "none"] },
              "fallback": { "type": "string" },
              "question": { "type": "string" }
            }
          }
        }
      }
    },
    "sections": {
      "type": "object",
      "additionalProperties": false,
      "description": "v3 template - 23 sections. Each section is either filled (object) or omitted (null). Omitted sections do not appear in the output document. Sections 1, 2, 4, 9, 13, 14, 20, 21 are never omitted (Locked 2).",
      "properties": {
        "summary": {
          "type": ["object", "null"],
          "description": "Section 1 - Geliştirme Özeti / Summary. Never null."
        },
        "goalsAndNonGoals": {
          "type": ["object", "null"],
          "description": "Section 2 - Hedefler ve Karşı Hedefler. Never null. Both columns mandatory (Locked 13)."
        },
        "flowChart": {
          "type": ["object", "null"],
          "description": "Section 3 - Akış Diyagramı. Mermaid blocks."
        },
        "userStories": {
          "type": ["object", "null"],
          "description": "Section 4 - Kullanıcı Hikayeleri. Gherkin format (Locked 12). Never null."
        },
        "designReference": {
          "type": ["object", "null"],
          "description": "Section 5 - Tasarım Referansı. All Figma variants drilled (Locked 18). Screenshots embedded (Locked 17)."
        },
        "componentInventory": {
          "type": ["object", "null"],
          "description": "Section 6 - Bileşen Envanteri."
        },
        "designTokens": {
          "type": ["object", "null"],
          "description": "Section 7 - Tasarım Token'ları."
        },
        "assetInventory": {
          "type": ["object", "null"],
          "description": "Section 8 - Asset Envanteri. SVG default for new assets (Locked 15)."
        },
        "apiContracts": {
          "type": ["object", "null"],
          "description": "Section 9 - API Kontratları. All response variants enumerated (Locked 17)."
        },
        "localization": {
          "type": ["object", "null"],
          "description": "Section 10 - Lokalizasyon. 8-locale full coverage for new keys (Locked 20)."
        },
        "analytics": { "type": ["object", "null"], "description": "Section 11 - Analytics." },
        "deeplinkPush": {
          "type": ["object", "null"],
          "description": "Section 12 - Deeplink ve Push Notification. Conditional."
        },
        "architecturePlan": {
          "type": ["object", "null"],
          "description": "Section 13 - Mimari Plan. Never null. Concept table filled by Pass B (Locked 22 + 24)."
        },
        "filesToAdd": {
          "type": "object",
          "description": "Section 14 - Eklenecek Dosyalar. Never null. Every row carries Reuse / Add new / Modify tag (Locked 16)."
        },
        "testPlan": { "type": ["object", "null"], "description": "Section 15 - Test Planı." },
        "accessibility": {
          "type": ["object", "null"],
          "description": "Section 16 - Erişilebilirlik."
        },
        "securityAndPrivacy": {
          "type": ["object", "null"],
          "description": "Section 17 - Güvenlik ve Gizlilik."
        },
        "rolloutPlan": { "type": ["object", "null"], "description": "Section 18 - Yayılım Planı." },
        "alternativesConsidered": {
          "type": ["object", "null"],
          "description": "Section 19 - Değerlendirilen Alternatifler. ADR format."
        },
        "risksAndOpenQuestions": {
          "type": ["object", "null"],
          "description": "Section 20 - Riskler ve Açık Sorular. Never null. Auto-populated from conventionRisks + reuse competitors."
        },
        "references": {
          "type": ["object", "null"],
          "description": "Section 21 - Referanslar. Never null. User-supplied input table at the bottom (Locked 21)."
        },
        "glossary": {
          "type": ["object", "null"],
          "description": "Section 22 - Sözlük (footer). Optional in Lite mode."
        },
        "changelog": {
          "type": ["object", "null"],
          "description": "Section 23 - Değişiklik Geçmişi (footer)."
        }
      },
      "required": [
        "summary",
        "goalsAndNonGoals",
        "userStories",
        "apiContracts",
        "architecturePlan",
        "filesToAdd",
        "risksAndOpenQuestions",
        "references"
      ]
    },
    "outputs": {
      "type": "object",
      "description": "Where the rendered per-platform documents were emitted (set across Phases 3, 3.5, 4).",
      "additionalProperties": false,
      "properties": {
        "draftDir": {
          "type": ["string", "null"],
          "description": "Scratch directory where per-platform drafts live before Phase 3.5 picker. Used by /multi-agent:resume."
        },
        "requested": {
          "type": "array",
          "description": "Destinations chosen by the user at Phase 3.5.",
          "items": { "type": "string", "enum": ["local", "confluence", "jira"] }
        },
        "localPaths": {
          "type": "array",
          "description": "One entry per per-platform-per-repo write (Phase 4 Local target).",
          "items": { "type": "string" }
        },
        "confluencePageUrls": {
          "type": "array",
          "description": "One entry per platform (Phase 4 Confluence target).",
          "items": { "type": "string", "format": "uri" }
        },
        "jiraIssueKey": {
          "type": ["string", "null"],
          "description": "Single issue receiving the combined description with `## Platform: X` separators (Phase 4 Jira target)."
        }
      }
    }
  }
}
