# Subagent Template — Validation & Manifest (Steps 10–12)

Validate IaC syntax, write `scaffold-manifest.json`, and generate deploy checklist. Follow the workflow below.

## Critical Rules

- ⛔ **Do NOT invoke ANY skills** — no `{"skill": "azure-validate"}`, `{"skill": "azure-deploy"}`, `{"skill": "azure-prepare"}`, or any other skill call. Use the procedures in THIS file only.
- ⛔ **Do NOT create or modify Azure resources** — validation is syntax-only (`bicep build` / `terraform validate`), never `az deployment sub create`.
- ⛔ **Do NOT run `what-if` or `terraform plan`** — deploy runs the mandatory what-if with real secret params. Scaffold validates syntax only.

## Input (provided by caller)

| Field | Required |
|-------|----------|
| IaC file paths (all generated `.bicep` or `.tf` files) | YES |
| Self-review findings from Steps 6–9 | YES |
| `prepare-plan.json` — services, naming, region, subscriptionId | YES |
| `prereq-output.json.warnings[]` — prereq warnings with `fixPhase` | YES |
| `prereq-output.json.healthEndpoint` — detected health path (or `null`) | YES |
| Conformance result JSON (from main-thread Step 10a-conf) | YES |

## Output

| Artifact | Location |
|----------|----------|
| `scaffold-manifest.json` | Session folder |
| `deploy-result.json` skeleton | Session folder |
| Validation result status | Return to caller: `Validated` or `Failed` |
| Deploy checklist | `.copilot-azure/sessions/{id}/deploy-checklist.md` |

## Workflow

### Step 1 — Read validation + manifest rules

Read [validation-and-manifest.md](validation-and-manifest.md) and [scaffold-schemas.ts](scaffold-schemas.ts).

**Do:** Understand the `ScaffoldManifest` interface (field names, types, required fields) and the validation sequence.

### Step 2 — Format and validate IaC

**Do:**
1. Run `az bicep build --file infra/main.bicep --stdout > $null` (Bicep) or `terraform validate` (TF). Process output for BCP errors and warnings. Record pass/fail.

### Step 3 — Check RBAC completeness

**Do:** Verify every managed identity ↔ resource pair in the IaC has a corresponding `Microsoft.Authorization/roleAssignments` resource with the correct role GUID. Cross-reference with the review findings from Steps 6–9 input.

### Step 3b — Azure runtime constraint check (Container Apps)

> Skip if no Container Apps in the plan.

For each Container App resource in the generated Bicep:

1. **cpu/memory combo** — verify `cpu` (must be type `string`) + `memory` is one of: `0.25/0.5Gi`, `0.5/1Gi`, `0.75/1.5Gi`, `1/2Gi`, `1.25/2.5Gi`, `1.5/3Gi`, `1.75/3.5Gi`, `2/4Gi`. FIXABLE: adjust to nearest valid combo (use smallest valid combo for sidecars/companions).
2. **secretRef coverage** — every `secretRef` in container env vars must have a matching entry in `configuration.secrets[]`. Every KV secret URL in `secrets[]` must reference a `Microsoft.KeyVault/vaults/secrets` resource that exists in the generated modules. Missing secret resource → FIXABLE: add it to the KV module.
3. **probe path** — if `prereq-output.json.healthEndpoint` is non-null, verify `probePath` matches it. If null AND any `plainEnvVars` entry is named `BASE` or `PATH_PREFIX`, verify `probePath` starts with that value (not bare `/`). If null AND no BASE var: verify the app has a route handler for the probe path (check source entry point for `app.get('/')` or framework root handler) — bare `/` on a REST API with only sub-path routes (e.g., `/users`, `/messages`) returns 404 and blocks revision activation. FIXABLE: update `probePath` to a known GET endpoint from the app.

FIXABLE errors: fix the Bicep → re-run `az bicep build` → proceed to Step 3c.

### Step 3b2 — App Service security constraint check

> Skip if no App Service or Functions in the plan.

For each App Service / Functions resource in the generated Bicep:

1. **basicPublishingCredentialsPolicies** — verify both child resources exist: `basicPublishingCredentialsPolicies/scm` (with `allow: true`) and `basicPublishingCredentialsPolicies/ftp` (with `allow: false`). Missing → FIXABLE: add the child resources per [bicep-patterns-security.md](bicep-patterns-security.md) § Publishing Credential Lockdown.
2. **uniqueString in naming** — verify the App Service name uses `uniqueString()` or a unique suffix (not a hardcoded literal). Hardcoded names cause global collisions. Missing → FIXABLE: wrap name with `uniqueString(resourceGroup().id)`.

FIXABLE errors: fix the Bicep → re-run `az bicep build` → proceed to Step 3c.

### Step 3c — Record plan conformance result

The main thread (SKILL.md Step 10a-conf) already ran the conformance script and passed you its JSON. Record it in `scaffold-manifest.json.conformance` = `{ passed, failures, source: "script" }`. ⛔ Do NOT set `validationResult.status: "Validated"` while any BLOCK failure is unresolved.

**Fallback** (only if the caller passed NO result AND `infra/main.bicep` exists — the gate is Bicep-only, skip for Terraform): run `{scaffoldDir}/scripts/scaffold-conformance.ps1 -SessionPath "{sessionPath}" -InfraPath infra` (or `.sh` on bash) yourself, then record with `source: "script"`. Never hand-judge when a shell is available.

### Step 4 — Write scaffold-manifest.json

Read [scaffold-schemas.ts](scaffold-schemas.ts) for exact field names.

**Do:** Write `scaffold-manifest.json` to the session folder with: `sessionId`, `scaffoldCompletedUtc`, `iacFormat`, `targetScope`, `entryPoint`, `parametersFile`, `files[]`, `deployCommand`, `twoPhaseWiring` (if Container Apps), `phase2Steps` (if applicable), `selfReview` (from caller input), `validationResult` (from Steps 2–3). Use the exact field names from [scaffold-schemas.ts](scaffold-schemas.ts) § `ScaffoldManifest`.

### Step 5 — Handle failures (if any)

Read [scaffold-healing-rules.md](scaffold-healing-rules.md) ONLY if validation failed.

**Do:** Classify errors as FIXABLE or BLOCKING. FIXABLE: auto-fix IaC → re-validate (max 3 attempts before asking user). BLOCKING: surface to user and halt. PLAN_LEVEL_CHANGE: requires re-approval — do NOT auto-fix.

### Step 6 — Verify deploy checklist exists

**Do:** Check that `.copilot-azure/sessions/{id}/deploy-checklist.md` exists (written by the parallel checklist subagent at scaffold Step 5b). If missing, read [`deploy-checklist-template.md`](../../deploy/references/deploy-checklist-template.md) and write it now as a fallback — fill `{placeholders}` from `prepare-plan.json`, delete non-applicable sections. This file survives conversation compaction

### Step 7 — Create deploy-result.json skeleton (MANDATORY)

Read [`deploy-schemas.ts`](../../deploy/references/deploy-schemas.ts) — specifically the `DeployResult` interface.

**Do:** Create `.copilot-azure/sessions/{id}/deploy-result.json` conforming to the `DeployResult` interface. Populate fields from all session artifacts already written (`prepare-plan.json`, `context.json`, `scaffold-manifest.json`, `prereq-output.json`). Use sensible defaults for fields the deploy phase will fill later. The deploy main agent updates this file in-place at Step 8 with real values.

### Step 8 — Return results

**Do:** Return validation status (`Validated` or `Failed`) to the caller. Confirm deploy-checklist.md exists. Keep status report ≤500 tokens.
