# 03-techspec.md — SDDL-3: Fix correção run SDD validation

**Artefato**: Tech Spec (Etapa 3)
**Card**: SDDL-3
**Data**: 2026-06-24
**Origem**: `docs/sddl-3/02-prd.md`
**Rastreabilidade**: `docs/sddl-3/03-techspec.md`

---

## 1. Rastreabilidade

| Campo | Valor |
|---|---|
| Card | SDDL-3 |
| PRD | `docs/sddl-3/02-prd.md` |
| Discovery | `docs/sddl-3/00-project-discovery.md` |
| Próximo artefato | `docs/sddl-3/04-tasks.md` |
| Código analisado | `src/main.rs` (`version_alignment_issues`, `cargo_toml_package_version`, `cargo_lock_package_version`, `is_layer_source_repo`) |

---

## 2. Visão técnica geral

O fix entrega scripts de bump atômico em `scripts/` que sincronizam `VERSION`, `Cargo.toml [package].version` e a entrada `sdd-layer` em `Cargo.lock` numa única invocação. Nenhuma lógica Rust é alterada; o alvo é o contrato de release que alimenta `version_alignment_issues`.

**Achados confirmados no codebase:**

1. **O nome do pacote é `sdd-layer`, não `sdd`.** `Cargo.toml:2` — `name = "sdd-layer"`; `sdd` é apenas o nome do binário (`[[bin]] name = "sdd"`, linha 10). A entrada em `Cargo.lock` é `name = "sdd-layer"`.
   **Consequência**: o RF-03 do PRD descreve `cargo update -p sdd`, que falharia. O comando correto é **`cargo update -p sdd-layer --precise <versão>`**.

2. **`version_alignment_issues` compara:** `VERSION` (trim), `cargo_toml_package_version` → primeira `version` sob `[package]`, e `cargo_lock_package_version` para `sdd-layer` (nome resolvido via `root.file_name()`).

3. **Modo estrito:** `is_layer_source_repo` retorna `true` quando `src/main.rs` + `plugins/orchestration/` coexistem → `strict_contract = true` → divergência vira FAILURE no CI.

4. **O CI roda só em `ubuntu-latest`** — o `.ps1` atende o fluxo local do mantenedor Windows.

5. **`scripts/` ainda não existe** no repo — criação nova.

---

## 3. Decisões arquiteturais

### AD-01 — Dois scripts (`.sh` + `.ps1`)

Bash no CI (ubuntu); PowerShell no dev local Windows. Sem Node/Python (viola RNF-03). Duplicação de ~60 linhas aceitável.

### AD-02 — Substituição cirúrgica em `Cargo.toml` (máquina de estado por seção)

Substituir **apenas a primeira `version = "..."` dentro de `[package]`**, replicando a heurística de `cargo_toml_package_version`:

```bash
# Bash (awk — sem sed -i)
awk -v v="$TARGET" '
  /^\[/ { inpkg = ($0 == "[package]") }
  inpkg && $1 == "version" && !done { print "version = \"" v "\""; done=1; next }
  { print }
' Cargo.toml > Cargo.toml.tmp && mv Cargo.toml.tmp Cargo.toml
```

PowerShell: mesma máquina de estado, leitura/escrita linha a linha. **Não** usar regex global — `Cargo.toml` tem `version` em várias dependências (linhas 19-37).

### AD-03 — `cargo update -p sdd-layer --precise <versão>`

Corrige erro no PRD (RF-03 especificava `-p sdd`). Flag `--precise` garante que apenas a entrada raiz no lock seja alterada, sem upgrades transitivos.

### AD-04 — Atomicidade via backup + rollback

Copiar `Cargo.toml` e `Cargo.lock` para `*.bak` antes de qualquer escrita. Ordem: TOML → lock (`cargo update`) → VERSION. Se `cargo update` falhar, restaurar os `.bak` e abortar antes de tocar `VERSION`. Em sucesso, remover `.bak`.

---

## 4. Estrutura de pastas

```
scripts/
  bump-version.sh      # fonte de verdade do CI
  bump-version.ps1     # dev local Windows
  README.md
```

`src/`, `.github/workflows/`, `plugins/` — intocados.

---

## 5. Contrato da interface

**Invocação:**
```
scripts/bump-version.sh <argumento>
scripts/bump-version.ps1 <argumento>
```

**Inputs:**

| Forma | Exemplo | Comportamento |
|---|---|---|
| Semver explícito | `0.16.0` | versão alvo = literal |
| `patch` | — | `0.15.2` → `0.15.3` |
| `minor` | — | `0.15.2` → `0.16.0` |
| `major` | — | `0.15.2` → `1.0.0` |

Versão base para incrementos: valor atual de `VERSION`.

**Exit codes:**

| Código | Significado |
|---|---|
| 0 | Sucesso; três arquivos sincronizados |
| 1 | Falha em `cargo update` ou I/O (rollback executado) |
| 2 | Argumento inválido (nada modificado) |

**Output (stdout):**
```
bump-version: 0.15.2 -> 0.16.0
  VERSION      0.16.0
  Cargo.toml   0.16.0
  Cargo.lock   0.16.0  (sdd-layer)
OK
```

---

## 6. Fluxo de execução com rollback

```
Argumento válido? → Não → exit 2 (nada tocado)
                 → Sim → resolver versão alvo
                          ↓
                         backup Cargo.toml.bak + Cargo.lock.bak
                          ↓
                         editar version sob [package] em Cargo.toml
                          ↓
                         cargo update -p sdd-layer --precise ALVO
                          → falha → restaurar .bak → exit 1
                          → OK →
                         escrever ALVO em VERSION
                          ↓
                         remover .bak
                          ↓
                         imprimir resumo → exit 0
```

---

## 7. Riscos técnicos

| ID | Risco | Severidade | Mitigação |
|---|---|---|---|
| RT-01 | PRD específica `-p sdd` (nome errado) | Alta | Usar `-p sdd-layer` (AD-03) |
| RT-02 | Replace cego corrompe versões de dependências | Alta | Máquina de estado por seção (AD-02) |
| RT-03 | `cargo update` puxa upgrades transitivos | Média | `--precise` + backup de `Cargo.lock` |
| RT-04 | Divergência `sed` GNU/BSD + ausência Windows | Média | `awk` no `.sh`, line-by-line no `.ps1` |
| RT-05 | Dessincronia se falha entre passos | Média | Rollback por backup (AD-04) |

---

## 8. Plano de implementação

**Criar:**
1. `scripts/bump-version.sh` — bash, `set -euo pipefail`, todas as etapas acima
2. `scripts/bump-version.ps1` — PowerShell, paridade funcional
3. `scripts/README.md` — uso, exit codes, RN-03

**Modificar:** nenhum arquivo de produção.
