fix: evita cache heuristico do navegador em GETs com Last-Modified #59

Merged
jhony75 merged 1 commit from fix/stale-get-cache into develop 2026-09-10 20:21:22 -03:00
Owner

Achado durante a verificacao manual do item 9 (Datasets, PR #58): GET /api/runs/{id} (e os outros 4 recursos que usam services/concurrency.py::set_last_modified_header -- reports, issues, requirements, technical-validations) manda Last-Modified sem Cache-Control. Como esse header nunca e bumpado quando uma colecao filha embutida na resposta muda (ex.: adicionar um cenario a um Run), o navegador aplica cache heuristico (RFC 7234, ~10% da idade Date-menos-Last-Modified) e pode servir uma resposta desatualizada por horas apos uma escrita -- confirmado comparando um fetch normal (dado velho) com fetch(url, {cache: "no-store"}) (dado correto) pra mesma URL.

Por que nao bumpar updated_at do pai em vez disso: Last-Modified aqui alimenta If-Unmodified-Since (concorrencia otimista) em check_not_modified_since. Bumpar o updated_at do Run toda vez que um cenario filho muda faria um PUT que so edita campos do proprio Run (nome/status) falhar com 412 espurio por causa de uma edicao completamente nao relacionada num filho -- pioraria a UX de concorrencia pra resolver um problema de cache. Cache-Control: no-store resolve o cache sem tocar nessa semantica.

Fix de um unico ponto em set_last_modified_header (helper compartilhado), cobre os 5 routers que usam o padrao. Teste novo confirma o header em GET e PUT; suite completa (191 testes) verde.

Achado durante a verificacao manual do item 9 (Datasets, PR #58): `GET /api/runs/{id}` (e os outros 4 recursos que usam `services/concurrency.py::set_last_modified_header` -- reports, issues, requirements, technical-validations) manda `Last-Modified` sem `Cache-Control`. Como esse header nunca e bumpado quando uma colecao filha embutida na resposta muda (ex.: adicionar um cenario a um Run), o navegador aplica cache heuristico (RFC 7234, ~10% da idade Date-menos-Last-Modified) e pode servir uma resposta desatualizada por horas apos uma escrita -- confirmado comparando um fetch normal (dado velho) com `fetch(url, {cache: "no-store"})` (dado correto) pra mesma URL. **Por que nao bumpar `updated_at` do pai em vez disso**: `Last-Modified` aqui alimenta `If-Unmodified-Since` (concorrencia otimista) em `check_not_modified_since`. Bumpar o `updated_at` do Run toda vez que um cenario filho muda faria um PUT que so edita campos do proprio Run (nome/status) falhar com 412 espurio por causa de uma edicao completamente nao relacionada num filho -- pioraria a UX de concorrencia pra resolver um problema de cache. `Cache-Control: no-store` resolve o cache sem tocar nessa semantica. Fix de um unico ponto em `set_last_modified_header` (helper compartilhado), cobre os 5 routers que usam o padrao. Teste novo confirma o header em GET e PUT; suite completa (191 testes) verde.
fix: evita cache heuristico do navegador em GETs com Last-Modified
All checks were successful
EEG QA CI / Detectar o que mudou (pull_request) Successful in 14s
EEG QA CI / Backend (pull_request) Successful in 1m16s
EEG QA CI / Frontend (pull_request) Has been skipped
EEG QA CI / Build e publicação de imagens (pull_request) Successful in 53s
EEG QA CI / Deploy production (pull_request) Has been skipped
EEG QA CI / Deploy development (pull_request) Has been skipped
b47c463d5e
Last-Modified em GET/PUT so existe pra alimentar If-Unmodified-Since
(concorrencia otimista) e nao e bumpado quando uma colecao filha
embutida na resposta muda (ex.: cenarios de um Run) -- de proposito,
pra nao gerar 412 espurio num PUT que so toca campos do pai. Sem
Cache-Control, porem, o navegador aplica cache heuristico (RFC 7234)
sobre esse header e pode servir um GET desatualizado por horas depois
de uma mudanca na colecao filha. Cache-Control: no-store no helper
compartilhado cobre os 5 routers que usam esse padrao (runs, reports,
issues, requirements, technical-validations) sem tocar na semantica
de concorrencia.
jhony75 merged commit 592e6ccc53 into develop 2026-09-10 20:21:22 -03:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jhony75/eeg-qa!59
No description provided.