# Validation Report Template

## Validator

Name: Codex Validation Agent

Stage Reviewed: Agent 04 - Projects, Tags, And Releases

Date: 2026-04-14

## Reviewed Inputs

- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
- `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
- `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
- `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
- `/Users/delete/projects/update_server/docs/agents/OPERATOR_QUICKSTART_RU.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/04-projects-releases.md`
- previous validation report: `/Users/delete/projects/update_server/docs/agents/validation/03-auth-validation.md`
- implementation files under `internal/db`, `internal/http`, `internal/releases`, `internal/storage`, `internal/slug`, `internal/app`, `internal/config`, and `web/templates`
- `GOCACHE=/tmp/go-build-agent04-validate GOMODCACHE=/tmp/go-mod-agent04-validate go test ./...` -> passed
- `GOCACHE=/tmp/go-build-agent04-validate GOMODCACHE=/tmp/go-mod-agent04-validate go build -o /tmp/update-server-agent04-validate ./cmd/server` -> passed
- `GOCACHE=/tmp/go-build-agent04-validate GOMODCACHE=/tmp/go-mod-agent04-validate go build -o /tmp/update-migrate-agent04-validate ./cmd/migrate` -> passed
- live smoke checks against `127.0.0.1:18083` after starting `/tmp/update-server-agent04-validate` with fresh bootstrap credentials and a fresh `DATA_DIR`:
  - `GET /admin/projects` without session -> `303 See Other` to `/admin/login?next=%2Fadmin%2Fprojects`
  - `POST /admin/login` -> `303 See Other` with session cookie
  - `GET /admin/projects` with session -> `200 OK`
  - `POST /admin/projects` -> project created
  - `POST /admin/tags` -> tag created
  - `POST /admin/projects/1/tags` -> tag attached
  - `POST /admin/projects/1/releases` with multipart file upload -> `303 See Other`
  - SQLite inspection confirmed project, tag, project-tag link, and release metadata rows
  - filesystem inspection confirmed artifact saved under `DATA_DIR/artifacts/...`, outside `web/static`
  - checksum of stored artifact matched `releases.checksum_sha256`
  - `POST /admin/tags/1/delete` while tag was still attached -> redirected with `tag-in-use`
  - `POST /admin/projects/1/archive` -> project became archived in SQLite and UI

## Findings

No blocking findings.

The stage satisfies the agreed scope:

- protected admin CRUD flows exist for projects and tags;
- project-tag assignment works;
- release uploads are stored under the private artifact directory;
- release metadata is persisted with sanitized filename, checksum, size, content type, storage path, and uploader linkage;
- archive and tag-in-use protection behaviors work in live validation.

## Required Fixes

None.

## Optional Improvements

- Add an explicit unit or integration test for rejecting uploads that exceed `MAX_UPLOAD_BYTES`.
- Consider surfacing a success flash on the projects list page for newly created items instead of only redirecting to detail pages.
- Add release disable/delete flows in a later stage when the product needs release lifecycle management beyond upload.

## Status

`APPROVED`
