# Set up the Sandbox Gate Hook

<!-- toolkit-version: 1.0.0 -->

## Overview

This setup file configures the toolkit's **Sandbox_Gate_Hook** for the current
workspace: a Kiro hook that, once a feature is implemented, deploys it to a
sandbox and runs a deterministic quality gate before a human reviews the pull
request.

The Sandbox_Gate_Hook is **optional** — it is only written when this workspace
has a `Deployable_Environment` (something that can be deployed to a sandbox or
provisioned via Infrastructure-as-Code). Workspaces that are local-only (e.g. a
script or library that is never deployed) do not need it; this file will say so
and stop without writing anything.

The workflow:

- Detecting whether the workspace has a `Deployable_Environment` by inspecting
  it for Infrastructure-as-Code, deploy scripts, CI deploy stages, or a
  declared hosting target
- If none found, reporting that the hook is not required and stopping
- If found, writing `.kiro/hooks/sandbox-gate.kiro.hook` with the toolkit's
  fixed hook definition
- Verifying the file was written correctly

## Parameters

None required. Detection is fully automatic from the contents of the workspace.
If detection is ambiguous (see Step 1's error handling), you MUST ask the user
to confirm whether the project has a deployable environment before proceeding.

## Dependencies

- You MUST have file read access to the workspace root to search for
  deployment signals.
- You MUST have file write access to create `.kiro/hooks/` if it does not
  already exist.
- You MUST NOT require Node.js, Python, or any other runtime or package
  manager — this file only reads and writes plain text/JSON.

## General error handling

If any step fails with an error not covered in that step's error handling
table, report the full error to the user and do not proceed to the next step.

## Steps

### Step 1: Detect whether the workspace has a Deployable_Environment

Search the workspace for **any** of the following signals:

| Signal | Look for |
|---|---|
| Infrastructure-as-Code | `*.tf`, `cdk.json`, `template.yaml`/`template.yml` (SAM), `serverless.yml`, `Pulumi.yaml`, Kubernetes manifests (`k8s/`, `kustomization.yaml`), CloudFormation templates |
| Deploy scripts | a `deploy` script in `package.json`, a `Makefile` target named `deploy`, a `deploy.sh` / `deploy.ps1` file, a `Procfile` |
| CI deploy stages | a job/step named `deploy` or `release` in `.github/workflows/*.yml`, `.gitlab-ci.yml`, `azure-pipelines.yml`, or a `Jenkinsfile` |
| Declared hosting target | `vercel.json`, `netlify.toml`, `apprunner.yaml`, `app.yaml`, `fly.toml`, `render.yaml`, `.platform/` |

**Success**: at least one signal found (project is deployable), or a confident
determination that none are present (project is local-only).

**Error handling**:

| Symptom | Cause | Resolution |
|---|---|---|
| Signals are mixed or ambiguous (e.g. a Makefile with a commented-out deploy target) | The workspace's deployment story is unclear from static inspection | Ask the user: "Does this project have an environment it can be deployed to (sandbox, staging, production), or is it local-only?" and proceed based on their answer |

Then:

- **No signal found** → tell the user the Sandbox_Gate_Hook is not required
  for this project and stop. Do not write any file.
- **At least one signal found** → proceed to Step 2.

### Step 2: Write the hook definition

Create `.kiro/hooks/` if it does not exist, then write the following file at
`.kiro/hooks/sandbox-gate.kiro.hook` exactly as shown. This is the toolkit's
fixed, deterministic hook definition — no substitution needed:

```json
{
  "name": "Sandbox Gate",
  "version": "1.0",
  "when": {
    "type": "agentStop",
    "condition": "feature-implementation-complete"
  },
  "then": {
    "type": "runQualityGate",
    "steps": ["deploy-sandbox", "run-quality-gate"],
    "timeoutMinutes": 10,
    "runsBeforePrReview": true,
    "qualityGate": {
      "deterministic": true,
      "categories": ["type errors", "security defects", "unverified behavior", "regressions", "spec drift"]
    },
    "onDeployFailureOrTimeout": { "blockPrReview": true, "error": true },
    "onQualityGateFail": { "blockPrReview": true, "reportFailedCategories": true },
    "onQualityGatePass": { "allowPrReview": true }
  }
}
```

**Success**: the file exists at `.kiro/hooks/sandbox-gate.kiro.hook` and is
valid JSON matching the content above exactly.

**Error handling**:

| Symptom | Cause | Resolution |
|---|---|---|
| Permission denied writing the file | No write access to `.kiro/hooks/` | Check directory permissions, or ask the user to create `.kiro/hooks/` manually, then retry |
| `.kiro/hooks/sandbox-gate.kiro.hook` already exists with different content | The hook was previously customized | Ask the user whether to overwrite it with the toolkit's definition or leave the existing customization in place |

### Step 3: Verify the hook

Read back `.kiro/hooks/sandbox-gate.kiro.hook`, parse it as JSON, and confirm
it has top-level keys `name`, `version`, `when`, and `then`, and that
`then.timeoutMinutes` is `10`.

**Success**: the file parses and the required keys and the 10-minute bound are
present.

**Error handling**:

| Symptom | Cause | Resolution |
|---|---|---|
| File does not parse as JSON | Write was interrupted or content was altered | Re-run Step 2 |
| Required keys missing | Wrong content was written | Re-run Step 2 with the exact JSON shown |

### Step 4: Confirm with the user

Tell the user: "The Sandbox Gate Hook is set up at
`.kiro/hooks/sandbox-gate.kiro.hook`. It will trigger when a feature is
finished, deploy it to a sandbox within 10 minutes, and run a quality gate
over five categories (type errors, security defects, unverified behavior,
regressions, spec drift) before the pull request is opened for human review."

Note one caveat explicitly: this hook defines the *trigger and policy* only —
the actual sandbox-deploy mechanism and quality-gate checks for `deploy-sandbox`
and `run-quality-gate` still need to be wired up in the project's own tooling
so something real runs when the hook fires.

Also remind the user that this hook's guarantees depend on the
[branch-protection prerequisite](../../docs/branch-protection-prerequisite.md)
being configured on `main` — without it, a merge can bypass the gate entirely.
