What happens
When @foreach (items as item) iterates a value that comes from a <script client> const, stx lowers it to a client @for loop. in the element's text is evaluated per row, but a inside a reactive attribute (:class, @click, ...) is carried into the output verbatim and never evaluated. The handler then receives the literal text and nothing reports it, so a click calls pick('').
Repro
<script client>
const tools = [{ id: 'woodcutter', label: 'Woodcutter' }]
const tool = state('')
function pick(kind: string): void { tool.set(kind) }
</script>
<!DOCTYPE html><html><head><title>t</title></head><body>
@foreach (tools as item)
<button type="button" :class="tool() === '' ? 'on' : 'off'" @click="pick('')">{{ item.label }}</button>
@endforeach
</body></html>buildStaticSite output:
<button type="button" :class="tool() === '' ? 'on' : 'off'" @click="pick('')" @for="item in tools" x-cloak>{{ item.label }}</button>In the browser the button label is right, but pick receives ; in a real app that surfaced as "Unknown building." from the game engine, and the :class comparison was never true.
Expected
Either the lowering rewrites a inside a reactive attribute of a client loop to the expression itself (pick(item.id)), or the build fails/warns that interpolation is not evaluated in :/@ attributes and points at the expression form. The working spelling today is :for="item in tools" with @click="pick(item.id)", which is not obvious from @foreach docs.
Found while building the playable demo on the Settlers III remake home page (stx 0.2.756).