[object Object]

← back to Model Arena

model-arena: preserve build-picker checkbox selection across the 4s detail poll

b4a8fe8200217fd67e27196c9352c6b7fa49955f · 2026-09-23 16:16:53 -0700 · Steve Abrams

renderDetail() rebuilt #d-build-picks on every openDetail() poll tick (4000ms while
a battle is still running), wiping the user's checked models back to the single
hardcoded default — the exact "select several while others still generate" case the
checkboxes were added for. Now applies the default only on the first render and
preserves the user's checked set on every subsequent rebuild. Caught by Cody.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01166faVcwiztzWqhHwD9yer

Files touched

Diff

commit b4a8fe8200217fd67e27196c9352c6b7fa49955f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 23 16:16:53 2026 -0700

    model-arena: preserve build-picker checkbox selection across the 4s detail poll
    
    renderDetail() rebuilt #d-build-picks on every openDetail() poll tick (4000ms while
    a battle is still running), wiping the user's checked models back to the single
    hardcoded default — the exact "select several while others still generate" case the
    checkboxes were added for. Now applies the default only on the first render and
    preserves the user's checked set on every subsequent rebuild. Caught by Cody.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01166faVcwiztzWqhHwD9yer
---
 public/index.html | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/public/index.html b/public/index.html
index a5ef6ca..90ccece 100644
--- a/public/index.html
+++ b/public/index.html
@@ -598,8 +598,18 @@ async function renderDetail(id, statusOnly){
       bbar.hidden=false;
       const def = c.winner || c.aiPick || doneRuns[0].model;
       // checkboxes, not a single-select — check ANY number of models and each
-      // gets its own independent iTerm2 Claude window + its own landing page
-      bpicks.innerHTML = doneRuns.map(r=>`<label title="${mLabel(r.model)} — its own iTerm2 window + landing page"><input type="checkbox" value="${r.model}"${r.model===def?' checked':''}> ${mLabel(r.model)}${r.model===c.winner?' 👑':(r.model===c.aiPick?' 🤖':'')}</label>`).join('');
+      // gets its own independent iTerm2 Claude window + its own landing page.
+      // PRESERVE the user's checked set across re-renders: openDetail() polls every
+      // 4s while a battle is still running, and this block rebuilds on every tick.
+      // Rebuilding blind would wipe the user's selection back to the default mid-battle
+      // (the exact "pick several while others still generate" case). So: default only on
+      // the FIRST render (no checkboxes yet); afterwards keep whatever is already checked.
+      const firstBuildRender = !bpicks.querySelector('input');
+      const prevChecked = new Set([...bpicks.querySelectorAll('input:checked')].map(i=>i.value));
+      bpicks.innerHTML = doneRuns.map(r=>{
+        const on = firstBuildRender ? (r.model===def) : prevChecked.has(r.model);
+        return `<label title="${mLabel(r.model)} — its own iTerm2 window + landing page"><input type="checkbox" value="${r.model}"${on?' checked':''}> ${mLabel(r.model)}${r.model===c.winner?' 👑':(r.model===c.aiPick?' 🤖':'')}</label>`;
+      }).join('');
       const updateBuildGo = ()=>{
         const n = bpicks.querySelectorAll('input:checked').length;
         bgo.textContent = n>1 ? `⚒ Build ${n} in iTerm2 (${n} windows)` : '⚒ Build in iTerm2';

← 6a61a4b Build 'The Form to Request a Form' satire strip from minicpm  ·  back to Model Arena  ·  Fix PT-06 stamp/label overlap and PT-03 ticket/face collisio b94f38e →