fix: MPS-24 Phase 2.8c — cache-bust ALL static JS (THE root cause)
THE root cause of the entire 'still reloads / still not working' saga
across 2.7 -> 2.8 -> 2.8b: shop_tags.j2 (tag_bulk.js) and
product_edit.j2 (product_tags.js) loaded their <script> WITHOUT the
?v={{ request.git_hash }} cache-bust. routes.py serves /static with
cache_max_age=3600, so the operator's browser kept the STALE JS for up
to an hour after every deploy — the new SPA code never executed, forms
fell back to native submit = full page reload, every time. Server-side
functional tests passed throughout because they have no browser cache.
Fix: append ?v={{ request.git_hash }} to EVERY static <script> include
(the established base.j2 / offer.js / pay-countdown.js convention) —
not just the two at fault but the whole latent class: tag_bulk,
product_tags, tag_filter, auction, player, sandbox, watch, signals,
comments, shop-settings. request.git_hash shifts every deploy -> URL
changes -> fresh fetch, no hard-refresh ever needed again.
Gate (must be empty):
grep -rnE '<script src="/static/js/[^"?]+\.js"' make_post_sell/templates/
The 2.8/2.8b JS (onTagFormClick unified click handler, AJAX focus,
drag-to-reorder) stands — it just was never being fetched by the
browser. 1131 tests pass. Docs: mps-24.md Phase 2.8c, CLAUDE.md
(new mandatory cache-bust convention section).
This commit is contained in:
parent
b15c0a0f38
commit
cd5ea68fe3
13 changed files with 46 additions and 13 deletions
17
CLAUDE.md
17
CLAUDE.md
|
|
@ -379,6 +379,23 @@ new comment into our DOM without a page reload (preserving media playback).
|
|||
Our server returns JSON (HTTP 201) for AJAX requests and falls back to our
|
||||
normal redirect flow on any error.
|
||||
|
||||
## Static Asset Cache-Busting (MANDATORY)
|
||||
|
||||
**Every `<script src="/static/...">` and `<link href="/static/...">` MUST
|
||||
end with `?v={{ request.git_hash }}`.** `routes.py` serves `/static` with
|
||||
`cache_max_age=3600`, so an un-versioned asset is cached by the browser
|
||||
for up to an hour — meaning a deploy that changes that JS/CSS is
|
||||
**invisible to users for up to an hour**. This manifests as "the new
|
||||
feature doesn't work / the SPA still full-reloads" even though the deploy
|
||||
landed and server-side tests pass (tests have no browser cache). This was
|
||||
the root cause of the entire MPS-24 tag-SPA debugging saga (5+ deploys).
|
||||
`request.git_hash` is a reified request method that shifts every deploy →
|
||||
URL changes → fresh fetch, no hard-refresh ever needed. Gate before
|
||||
commit (must be empty):
|
||||
```
|
||||
grep -rnE '<script src="/static/js/[^"?]+\.js"' make_post_sell/templates/
|
||||
```
|
||||
|
||||
## CI/CD Notes
|
||||
|
||||
- Build uses `virtualenv-clone` which requires `bin/python` symlink (Python 3.12 `venv` may only create `python3`)
|
||||
|
|
|
|||
|
|
@ -363,6 +363,22 @@ Tests (`test_functional.py::TestProductTagsSpa`):
|
|||
Deferred (occasional click, not the hot path): AJAX-ifying the
|
||||
"Suggest categories" link — still a full navigation by design.
|
||||
|
||||
**Phase 2.8c — THE root cause** (shipped 2026-05-16): every "still
|
||||
reloads / still not working" report across 2.7 → 2.8 → 2.8b was the
|
||||
**same defect** — `shop_tags.j2` (`tag_bulk.js`) and `product_edit.j2`
|
||||
(`product_tags.js`) loaded their `<script>` **without**
|
||||
`?v={{ request.git_hash }}`. `/static` is served
|
||||
`cache_max_age=3600`, so the operator's browser kept the stale JS for
|
||||
up to an hour after every deploy: the new SPA code never ran, forms
|
||||
fell back to native submit = full reload, every time — while
|
||||
JS-blind server tests passed. Fix: append `?v={{ request.git_hash }}`
|
||||
to **all** static `<script>` includes (the existing `base.j2` /
|
||||
`offer.js` convention), not just the two — same latent bug class
|
||||
across `tag_filter`, `auction`, `player`, `sandbox`, `watch`,
|
||||
`signals`, `comments`, `shop-settings`. Grep gate:
|
||||
`grep -rnE '<script src="/static/js/[^"?]+\.js"' templates/` must be
|
||||
empty. (The 2.8/2.8b JS work stands; it just was never being fetched.)
|
||||
|
||||
**Phase 2.8b** (shipped 2026-05-16): the generic `data-tag-form`
|
||||
**`submit`-event** interception proved unreliable in the field —
|
||||
operator reported Add / Delete / reorder *all* still full-reloaded
|
||||
|
|
|
|||
|
|
@ -102,5 +102,5 @@
|
|||
|
||||
</section>
|
||||
|
||||
<script src="/static/js/auction.js"></script>
|
||||
<script src="/static/js/auction.js?v={{ request.git_hash }}"></script>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@
|
|||
<div id="sandbox-actions" class="sandbox-actions"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/js/sandbox.js"></script>
|
||||
<script src="/static/js/sandbox.js?v={{ request.git_hash }}"></script>
|
||||
{% endif %}
|
||||
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -204,8 +204,8 @@ function playInline(container, videoUrl) {
|
|||
}
|
||||
</script>
|
||||
{% if request.shop.watch_mode_enabled %}
|
||||
<script src="/static/js/watch.js"></script>
|
||||
<script src="/static/js/watch.js?v={{ request.git_hash }}"></script>
|
||||
{% endif %}
|
||||
<script src="/static/js/signals.js"></script>
|
||||
<script src="/static/js/signals.js?v={{ request.git_hash }}"></script>
|
||||
|
||||
{%- endblock -%}
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@
|
|||
</section>
|
||||
{% endif %}
|
||||
|
||||
<script src="/static/js/tag_filter.js" defer></script>
|
||||
<script src="/static/js/tag_filter.js?v={{ request.git_hash }}" defer></script>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/player.js"></script>
|
||||
<script src="/static/js/player.js?v={{ request.git_hash }}"></script>
|
||||
<script>
|
||||
// Pass navigation data to player.js
|
||||
window.playerData = {
|
||||
|
|
|
|||
|
|
@ -374,8 +374,8 @@ function playInline(container, videoUrl) {
|
|||
}
|
||||
</script>
|
||||
{% if request.shop.watch_mode_enabled %}
|
||||
<script src="/static/js/watch.js"></script>
|
||||
<script src="/static/js/watch.js?v={{ request.git_hash }}"></script>
|
||||
{% endif %}
|
||||
<script src="/static/js/signals.js"></script>
|
||||
<script src="/static/js/signals.js?v={{ request.git_hash }}"></script>
|
||||
|
||||
{%- endblock -%}
|
||||
|
|
|
|||
|
|
@ -630,6 +630,6 @@
|
|||
|
||||
</div>
|
||||
|
||||
<script src="/static/js/product_tags.js" defer></script>
|
||||
<script src="/static/js/product_tags.js?v={{ request.git_hash }}" defer></script>
|
||||
|
||||
{%- endblock -%}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,6 @@
|
|||
</div> {# /.tag-detail-layout #}
|
||||
{% endif %}
|
||||
|
||||
<script src="/static/js/tag_filter.js" defer></script>
|
||||
<script src="/static/js/tag_filter.js?v={{ request.git_hash }}" defer></script>
|
||||
|
||||
{%- endblock -%}
|
||||
|
|
|
|||
|
|
@ -1628,7 +1628,7 @@ function toggleCryptoWallets() {
|
|||
timer = setInterval(poll, 4000);
|
||||
})();
|
||||
</script>
|
||||
<script src="/static/js/shop-settings.js"></script>
|
||||
<script src="/static/js/shop-settings.js?v={{ request.git_hash }}"></script>
|
||||
|
||||
{%- endblock -%}
|
||||
|
||||
|
|
|
|||
|
|
@ -174,6 +174,6 @@
|
|||
</ul>
|
||||
</section>
|
||||
|
||||
<script src="/static/js/tag_bulk.js" defer></script>
|
||||
<script src="/static/js/tag_bulk.js?v={{ request.git_hash }}" defer></script>
|
||||
|
||||
{%- endblock -%}
|
||||
|
|
|
|||
|
|
@ -133,5 +133,5 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<script src="/static/js/comments.js"></script>
|
||||
<script src="/static/js/comments.js?v={{ request.git_hash }}"></script>
|
||||
{% endif %}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue