{"record":{"id":"5687f85bceadd436","repo":"Hmbown/CodeWhale","slug":"the-practice-text-field-changed-run-the-check-again","errorCode":null,"errorMessage":"The practice text field changed. Run the check again.","messagePattern":"The practice text field changed\\. Run the check again\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"crates/tui/plugins/computer-use/app/background-check.mjs","lineNumber":65,"sourceCode":"    const state = await call(\"get_app_state\");\n    if (demoDirectory) {\n      fs.mkdirSync(demoDirectory, { recursive: true });\n      // AX can register before WindowServer makes a new window capturable.\n      // Retry only this read, before sending any input, within the check limit.\n      while (true) {\n        try { await call(\"screenshot\", { app_ref: { pid: child.pid }, path: path.join(demoDirectory, \"01-ready.png\") }); break; }\n        catch (error) {\n          if (controller.signal.aborted || !error.message.includes(\"not capturable\")) throw error;\n          await delay(100, undefined, { signal: controller.signal });\n        }\n      }\n    }\n    const entry = state.elements.find(element => element.role === \"AXTextField\" && element.label === \"Practice text\");\n    const apply = state.elements.find(element => element.role === \"AXButton\" && element.label === \"Apply\");\n    if (!entry || !apply) throw new Error(\"The practice controls could not be read. Check Accessibility permission and retry.\");\n    // Backend targets are resolved AX records, using the exact state index.\n    const focus = await call(\"resolve_element\", { app_ref: { pid: child.pid }, windowIndex: entry.windowIndex, path: entry.path });\n    if (!focus.found) throw new Error(\"The practice text field changed. Run the check again.\");\n    await call(\"left_click\", { target: { ...focus.element, type: \"element\", app_ref: { pid: child.pid } } });\n    const phrase = \"Background check complete 🐋\";\n    await call(\"type\", { text: phrase });\n    if (demoDirectory) await call(\"screenshot\", { app_ref: { pid: child.pid }, path: path.join(demoDirectory, \"02-entered.png\") });\n    const button = await call(\"resolve_element\", { app_ref: { pid: child.pid }, windowIndex: apply.windowIndex, path: apply.path });\n    if (!button.found) throw new Error(\"The practice Apply button changed. Run the check again.\");\n    await call(\"left_click\", { target: { ...button.element, type: \"element\", app_ref: { pid: child.pid } } });\n    await until(() => applied);\n    if (applied.value !== phrase) throw new Error(\"The text received by the practice window did not match. Check the app log and retry.\");\n    const capture = await call(\"screenshot\", { app_ref: { pid: child.pid }, path: path.join(scratch, \"practice.png\") });\n    if (demoDirectory) fs.copyFileSync(capture.file, path.join(demoDirectory, \"03-verified.png\"));\n    if (capture.app_ref?.pid !== child.pid || !capture.pixels?.w || !capture.pixels?.h) throw new Error(\"The practice window screenshot could not be verified. Check Screen Recording permission.\");\n    const count = latest.samples;\n    await until(() => latest.samples > count);\n    const isolated = latest.samples > 0 && latest.pointerChanges === 0 && latest.foregroundChanges === 0;\n    return { ok: isolated, edited: true, screenshot: true, samples: latest.samples, pointerChanges: latest.pointerChanges, foregroundChanges: latest.foregroundChanges,\n      message: isolated ? \"Text entered, Apply verified and the practice window captured. Your foreground app and pointer stayed unchanged.\"\n        : \"Edit and screenshot verified. Your app or pointer moved during the check, so background isolation is inconclusive.\" };","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/app/background-check.mjs#L47-L83","documentation":"The check resolves the located 'Practice text' AX element to a concrete backend target via resolve_element. If the reply says found: false, the element record captured moments earlier no longer matches the live UI — the field's AX path or window changed between snapshot and resolution. The error asks you to rerun so a fresh snapshot is taken.","triggerScenarios":"In runBackgroundCheck, call('resolve_element', { app_ref: { pid: child.pid }, windowIndex: entry.windowIndex, path: entry.path }) returns { found: false } after the text field was found in the state snapshot.","commonSituations":"The practice window moved, reopened, or re-indexed between get_app_state and resolve_element; UI animations delaying layout; another window stealing focus and changing window order.","solutions":["Re-run the background check — a fresh state snapshot usually resolves the element successfully.","Run the check on a quiet desktop (no other apps opening/closing) so AX indices stay stable.","If it reproduces every time, capture app logs and report an AX indexing bug against the practice app."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await runBackgroundCheck({ bundle });\n} catch (e) {\n  if (String(e.message).includes(\"practice text field changed\")) {\n    return runBackgroundCheck({ bundle }); // stale AX snapshot — one retry\n  }\n  throw e;\n}","preventionTips":["Keep the desktop static (no window open/close/focus churn) while the check runs.","Retry on stale-element messages before treating the check as failed.","Report recurring cases with app logs — they usually indicate AX indexing bugs, not user error."],"tags":["accessibility","stale-reference","race","computer-use"],"backgroundTag":"resource-not-found","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}