# Artifact Promotion

## Overview

Tawa uses artifact promotion to move builds through environments without rebuilding. Build once in sandbox, promote the same image to UAT, then to production.

## Promotion Path

```
sandbox (full build + deploy)
  → UAT (image reuse, Helm upgrade only, ~1 min)
    → prod (image reuse + HIL approval required)
```

## CLI Commands

### Promote to next environment
```bash
tawa promote --to uat          # sandbox → UAT
tawa promote --to prod --yes   # UAT → prod (requires --yes for prod)
tawa promote --to uat --force  # bypass gate checks
```

### Check deployment gates
```bash
tawa gates status              # show gate status for current environment
tawa gates status --env prod   # check prod gates
tawa gates status --json       # machine-readable output
```

### Approve production promotion (HIL gate)
```bash
tawa approve                   # approve pending promotion
tawa approve --build <id>      # approve specific build
```

### Approving a commit for a gated production deploy

Services enrolled in the deploy-approval gate need a sign-off on the **exact commit** before
`tawa deploy --prod` will build. Approve the commit, then deploy:

```bash
tawa approve --commit 586badb --env prod   # short SHA (7+ hex chars) is fine
tawa deploy --prod
```

The builder resolves a short SHA to the full 40-character SHA **at approval time**, through
Forgejo, and stores only the full SHA. `tawa approve` prints the commit it actually approved.
An approval is single-use and expires after 24 hours.

| You passed | Result |
|------------|--------|
| Full 40-char SHA | Stored as given |
| Unique 7–39 char prefix | Resolved to the full SHA and stored |
| Prefix that is unknown **or ambiguous** in the repo | Refused, `422 UNKNOWN_COMMIT` — pass the full SHA |
| Not 7–40 hex chars (`main`, `586bad`) | Refused, `400 INVALID_COMMIT` |

If Forgejo cannot be asked (repo elsewhere, Forgejo down), the builder falls back to this
service's build history: one matching built commit is accepted, more than one is refused with
`422 AMBIGUOUS_COMMIT`.

> **Fixed 2026-10-04 (iec-builder#256).** The approve route used to store the SHA exactly as
> typed, while the gate matches the full SHA exactly. `tawa approve --commit 586badb` reported
> success and the next deploy was still `BLOCKED: no valid, unconsumed approval`. Short-SHA
> approvals made before the fix never match; re-approve, or let them expire.

### View platform versions
```bash
tawa versions                  # list all version snapshots
tawa versions show v1.0.0      # show service matrix for a version
tawa versions diff v1.0.0 v1.1.0  # compare two versions
```

### Check for breaking changes
```bash
tawa upgrade                   # show migration guide for your service
tawa upgrade --json            # machine-readable output
```

## Deployment Gates

Gates are checks that must pass before promotion is allowed. They don't block deployment — only promotion.

| Gate | What it checks | Required? |
|------|---------------|-----------|
| security | Dependency vulnerability scan | Yes |
| integration | Service-to-service connectivity | Yes |
| soak | Minimum time deployed (2 hours) | Yes |
| hil | Human-in-the-loop approval | Prod only |
| compliance | Septor audit trail + Wallet events | Yes |

### Gate behavior
- Gates are evaluated at promotion time, not at deploy time
- `--force` bypasses all gates (logged to Septor audit trail)
- HIL approvals expire after 24 hours
- All promotions are audited via Septor

## How It Works (Technical)

1. `tawa deploy` builds and deploys to sandbox (full pipeline)
2. `tawa promote --to uat` calls builder API which:
   - Finds the latest completed build in sandbox
   - Verifies all gates pass (or `--force`)
   - Creates a new Build record reusing the same Docker image
   - Deploys to UAT namespace via Helm (no Docker build)
3. `tawa promote --to prod --yes` does the same UAT → prod, plus:
   - Requires a valid HIL approval (from `tawa approve`)
   - Records the promotion in Koko's promotion registry
   - Emits `promotion.completed` Septor audit event

## Septor Audit Events

| Event | When | Data |
|-------|------|------|
| `promotion.completed` | After successful promotion | serviceId, environments, imageTag, force flag |
| `promotion.approved` | After HIL approval | serviceId, buildId, approvedBy, expiresAt |

## PolicyEco Versions

A PolicyEco version is a snapshot of all platform services at specific image SHAs. Use versions to:
- Pin your app to a known-good platform state
- Detect breaking changes before upgrading
- Track what changed between platform releases

```bash
# Target a specific platform version during local dev
tawa dev --platform-version v1.0.0
```

## Best Practices

1. Always deploy to sandbox first — never promote from nothing
2. Let the soak gate do its job — don't `--force` just to go faster
3. Run `tawa gates status` before promoting to catch issues early
4. Use `tawa upgrade` to check for breaking changes before updating
5. HIL approvals are personal — the approver is recorded in the audit trail
