# F5.I3.T4 — Fronteira de storage: o service Media é o único dono

| Campo | Valor |
|---|---|
| **Fase** | F5 — Borda |
| **Issue** | F5.I3 — Cache, resposta e hardening (plano 18) |
| **kd task** | `task_01o91fam` |
| **Âncora** | `wiki/implementation/05-borda.md` |
| **Status da revisão** | 🔧 com correções |

## O que foi implementado

- `tests/Feature/StorageBoundaryTest.php` (escrito **antes**): capturou `Demo/ProcessMilestoneMedia`
  (código morto com `Storage::disk('local')` + `Str::random(5)`) — removido para `.pi/trash/`.
- Regra em **AST** no `tools/arch-check` (`isStorageApi`): fora de `src/services/Media/**` e de
  `src/core/Internal/System/Storage/**`, qualquer import de `Storage`/Flysystem/`Aws\*` ou chamada
  `Storage::` falha o build; fixtures `storage-{invalid,valid,owner-valid}` no `gates-selftest`.
- O teste estrutural também fixa `services.media.disk=s3` e `env('FILESYSTEM_DISK','s3')` /
  `env('MEDIA_DISK','s3')`; `Storage::fake()` em `**/Test/**` fica fora (dublê de teste).

## Arquivos para revisar

- `tests/Feature/StorageBoundaryTest.php`
- `tools/arch-check` (+ `tools/tests/fixtures/arch/storage-*`)
- `tools/gates-selftest.sh`
- `src/services/Media/Storage/SecureMediaStorage.php`
- `src/core/Internal/System/Storage/**` (provisionamento de bucket)

## Pontos de revisão

### PHP 8.4 / Laravel 12
- [ ] `declare(strict_types=1)`; DI por construtor (sem `new`/`app()`/`resolve()` no corpo); PHPStan `max`.
- [ ] Nativo primeiro; sem closure em rota; `env()` só em `config/`; validação em `FormRequest`.

### Determinismo (ADR-001)
- [ ] `Clock`/`IdGen` injetados; ordem explícita; idempotência provada por teste.

### Fronteiras (ADR-013/014/015)
- [ ] Camadas respeitadas; módulo consome `Services\{Name}\{Contracts,DTOs,Enums}\*`; nada de storage fora do Media.

### HTML/a11y (ADR-025) e CSS (ADR-010)
- [ ] Semântica, rótulos, alvos; sem `!important`/inline/CDN; `oklch`/`rem`.

### i18n (ADR-012)
- [ ] Nenhuma string visível fixa — inclusive **títulos de erro lançados em PHP** (o `ModuleI18nTest` só varre views).

### Dados (ADR-007/017) e segurança (ADR-020/021/026/030/035)
- [ ] `text`/`jsonb`/`uuidv7()`; `down()` → `backup_*`; CHECKs; PII cifrada; `throttle`; MIME real; `alt` obrigatório.

### Observabilidade/auditoria (ADR-024/035)
- [ ] Span + `log_event` com o **mesmo** `{service}.{action}`; auditoria via `AuditWriter`; sem PII.

### Específicos desta task

- [ ] Nenhum módulo/service/layout importa `Storage`/Flysystem/AWS (AST + teste estrutural).
- [ ] Disco padrão `s3` com fallback **na leitura** também (upload não "some").
- [ ] Quarentena `staging/` nunca servida pelo stream público.

## Comandos úteis

```bash
make check              # caminho único (rápido)
make check E2E=1        # + Playwright/axe/perf (2× ao fechar o escopo)
```

---

> Revisar contra `AGENTS.md`, `wiki/adr/` e o plano citado. Registrar achados no `kd` (`kd write --anchor`) e, se houver correção, teste de regressão.

## Notas da revisão

| Data | Revisor | Resultado | Observações |
|---|---|---|---|
| 2026-10-19 | agente (PROTOCOLO v2.0) | 🔧 | **A** (médio, D13/D4) o `arch-check` permite `services → services` **inteiros**: `Gallery`
importa `Services\Media\Models\MediaUpload`/`MediaBatch` (modelos = implementação do outro
serviço), contrariando o espírito da ADR-015 (consumir `Contracts/DTOs/Enums`) e sem gate que
perceba → `task_01gpf5qd`. **Verificado OK**: `StorageBoundaryTest` + regra AST + fixtures; disco
`s3` com fallback nos dois sentidos; quarentena isolada. |

> Resultado: `✅ revisado` · `🔧 com correções` · `⏭️ delegado` (com justificativa).
