Bound the hand, greek the copy, and treat waiting as supervision

A codex field run dealt six challengers into an eight-sketch batch
behind an opaque subagent, and the user stared at a page of shimmer
asking whether anything was happening at all. Four fixes from that run.
A hand now holds at most three challengers, the rest banked for
re-rolls, so fairness within the hand stops multiplying into a queue.
Sketches greek everything but the product's real name and one real
headline, because an invented spec, price, or ship date in a sketch is
a claim PRODUCT.md never made, and comps have solved this for a century.
Sketch production follows the user's reading order with the first file
doubling as the producer's heartbeat, and the parent's --wait loop
checks the sketch directory each pass, reclaiming the batch inline when
two minutes pass with nothing landed. And a failed --start now captures
the daemon's stderr to a per-key log and names the sandbox as the usual
suspect, instead of reporting only that failure occurred. The shimmer
counts its elapsed seconds, and gives up at 150 instead of 300.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-07-27 17:49:21 -07:00
co-authored by Claude Fable 5
parent 149d71a772
commit 0eb443d29b
3 changed files with 21 additions and 7 deletions
+18 -4
View File
@@ -222,14 +222,25 @@ if (hasFlag('start')) {
const key = arg('key') || Math.random().toString(16).slice(2, 10);
// In start mode the agent is alive and owns browser routing; the server
// only opens the system browser itself when --open forces it.
// The daemon's output lands in a per-key log so a startup failure can say
// what actually went wrong instead of only that it did.
const logFile = path.join(QUESTION_DIR, `${key}.log`);
const logFd = fs.openSync(logFile, 'a');
const child = spawn(process.execPath, [
fileURLToPath(import.meta.url), '--payload', payloadPath, '--detached-serve', '--key', key,
'--timeout', String(timeoutSec), ...(hasFlag('open') ? [] : ['--no-open']),
], { detached: true, stdio: 'ignore' });
], { detached: true, stdio: ['ignore', logFd, logFd] });
child.unref();
fs.closeSync(logFd);
const deadline = Date.now() + 8000;
while (Date.now() < deadline && !fs.existsSync(stateFile(key))) await new Promise((r) => setTimeout(r, 100));
if (!fs.existsSync(stateFile(key))) { console.error('serve-question: server failed to start'); process.exit(1); }
if (!fs.existsSync(stateFile(key))) {
let tail = '';
try { tail = fs.readFileSync(logFile, 'utf8').trim().split('\n').slice(-4).join('\n '); } catch { /* log never written */ }
console.error(`serve-question: server failed to start${tail ? `\n ${tail}` : ''}`);
console.error(`serve-question: log at ${path.relative(process.cwd(), logFile) || logFile}. A sandboxed exec that cannot listen on localhost causes exactly this; rerun this command once through the harness's network-enabled or unsandboxed command tool before falling back.`);
process.exit(1);
}
const state = JSON.parse(fs.readFileSync(stateFile(key), 'utf8'));
console.log(`QUESTION URL: ${state.url}`);
console.log(`QUESTION KEY: ${key}`);
@@ -617,13 +628,16 @@ function page() {
document.querySelectorAll('.media.sketching').forEach(m => {
const url = m.dataset.sketch;
const img = m.querySelector('img.sketch');
const note = m.querySelector('.sketch-note');
const started = Date.now();
const settle = () => { m.classList.remove('sketching'); m.querySelector('.shimmer')?.remove(); };
// A live elapsed count is the difference between "working" and "frozen".
const tick = setInterval(() => { if (note) note.textContent = 'sketching · ' + Math.round((Date.now() - started) / 1000) + 's'; }, 1000);
const settle = () => { clearInterval(tick); m.classList.remove('sketching'); m.querySelector('.shimmer')?.remove(); };
const tryLoad = () => {
const probe = new Image();
probe.onload = () => { img.src = probe.src; img.hidden = false; settle(); };
probe.onerror = () => {
if (Date.now() - started > 300000) {
if (Date.now() - started > 150000) {
const pip = m.querySelector('.pip img');
if (pip) { img.src = pip.getAttribute('src'); img.hidden = false; }
else { m.closest('.face').classList.add('text-only'); m.remove(); }