Reload a ChatGPT page that drew the bound answer blank instead of treating it as a changed head #75

Merged
xicv merged 6 commits from fix/unrendered-head-reload into main 2026-09-23 13:47:41 +00:00
xicv commented 2026-09-23 13:47:31 +00:00 (Migrated from github.com)

Summary

After the Ego Lite restart on 2026-09-23, ego_verify_conversation on claude-code-live-check failed twice with conversation_head_changed (tail_content_changed). Nothing in the chat had changed.

Cause, from read-only checks of the live tabs:

  • Ego Chat's own tab loaded at 13:20:42. Five of ChatGPT's own scripts (chatgpt.com/cdn/assets/*.js) failed together 1.6 s into that load, all with status 0 and 0 bytes.
  • The page then drew every answer as an empty message node (32 px, no .markdown), while user messages still showed. It stayed that way for over six minutes.
  • The driver read the bound answer as empty text. So the recorded head (same message ID, text "OK" plus the end marker) looked changed.
  • A fresh tab on the same ChatGPT build loaded all its scripts and drew every answer.

Why it matters beyond verify:

  • Without "Pro only", a Send on such a page is re-anchored automatically to the blank answer, and then Sends on a page that cannot draw the reply.
  • Under "Pro only", the reload before each Send is itself a fresh page load, and can come up the same way.

Fix:

  • Detection. tailUnrendered flags a last assistant answer with no text; an image-only turn is excluded. After the existing one-second hydration re-read, stabilizeBoundHead reports such a tail as unrendered instead of changed.
  • One proven reload. The exchange's first head read and verify reload the page once, then read it again. The proof steps are extracted from the Pro only reload into reloadSelectedPage: page marker, later performance.timeOrigin, same target and URL, task-space revalidation and readiness.
    • The Pro only reload keeps its scripts, phases and failure reasons unchanged.
    • The head reload has its own marker (ego-chat-head-reload), phases, stage (reloading_unrendered_page) and one-per-run budget. A policy reload that comes up blank can therefore still get its head reload.
    • After a head reload, the exchange repeats its composer-surface and generation checks, and verify repeats its generation check.
  • New stop code. An answer still blank after the reload, or blank again at the pre-compose re-read, stops as conversation_head_unrendered, never as conversation_head_changed, so the broker never re-anchors to it.
    • It is a retryable pre-Send reason, and each retry loads a fresh page.
    • The new stage counts as pre-click and pre-composition.
    • The head reload's failure steps are recorded as fixed uiReasons.
  • Re-anchor guard. Re-anchoring refuses a blank answer.
  • Longer verify budget. Verify's driver budget goes from 60 s to 120 s, and the CLI and MCP requests wait 125 s, so one reload fits even at its worst case (30 s navigation, 10 s proof, 10 s readiness).

No binding was anchored to a blank answer: all 41 were checked for the empty-text digest. Browser contract 34, runtime generation 2026-09-23.13.

Verification

  • Tests written first and seen failing:
    • verify reloads once and passes;
    • still blank after one reload gives conversation_head_unrendered;
    • an answer drawn with other text is still conversation_head_changed with no reload;
    • re-anchoring refuses a blank answer;
    • an exchange reloads once as a fenced stage, then sends;
    • a "Pro only" exchange gets both reloads;
    • still blank stops before anything is composed;
    • the broker retries the new code without re-anchoring;
    • a driver error in the new stage is a proven pre-Send failure.
  • npm test: 1417 tests, 1416 pass, 1 skipped. npm run test:ego-monitor 148/148. Receipt suite 16/16. ESLint clean on changed files. A3K fixture regenerated.
  • Codex review (read-only, --base aab36cb): no actionable regression. Its sandbox could not create temporary directories, so the suites above ran locally.
  • Codex review of the shared verify timeouts (read-only, last commit only): no actionable regression.

Live check after install

Ego Chat's broken tab is still open in Space 1. ego-chat verify claude-code-live-check should reload it once and pass.

## Summary After the Ego Lite restart on 2026-09-23, `ego_verify_conversation` on `claude-code-live-check` failed twice with `conversation_head_changed` (`tail_content_changed`). Nothing in the chat had changed. **Cause, from read-only checks of the live tabs:** - Ego Chat's own tab loaded at 13:20:42. Five of ChatGPT's own scripts (`chatgpt.com/cdn/assets/*.js`) failed together 1.6 s into that load, all with status 0 and 0 bytes. - The page then drew every answer as an empty message node (32 px, no `.markdown`), while user messages still showed. It stayed that way for over six minutes. - The driver read the bound answer as empty text. So the recorded head (same message ID, text "OK" plus the end marker) looked changed. - A fresh tab on the same ChatGPT build loaded all its scripts and drew every answer. **Why it matters beyond verify:** - Without "Pro only", a Send on such a page is re-anchored automatically to the blank answer, and then Sends on a page that cannot draw the reply. - Under "Pro only", the reload before each Send is itself a fresh page load, and can come up the same way. **Fix:** - **Detection.** `tailUnrendered` flags a last assistant answer with no text; an image-only turn is excluded. After the existing one-second hydration re-read, `stabilizeBoundHead` reports such a tail as `unrendered` instead of `changed`. - **One proven reload.** The exchange's first head read and verify reload the page once, then read it again. The proof steps are extracted from the Pro only reload into `reloadSelectedPage`: page marker, later `performance.timeOrigin`, same target and URL, task-space revalidation and readiness. - The Pro only reload keeps its scripts, phases and failure reasons unchanged. - The head reload has its own marker (`ego-chat-head-reload`), phases, stage (`reloading_unrendered_page`) and one-per-run budget. A policy reload that comes up blank can therefore still get its head reload. - After a head reload, the exchange repeats its composer-surface and generation checks, and verify repeats its generation check. - **New stop code.** An answer still blank after the reload, or blank again at the pre-compose re-read, stops as `conversation_head_unrendered`, never as `conversation_head_changed`, so the broker never re-anchors to it. - It is a retryable pre-Send reason, and each retry loads a fresh page. - The new stage counts as pre-click and pre-composition. - The head reload's failure steps are recorded as fixed `uiReason`s. - **Re-anchor guard.** Re-anchoring refuses a blank answer. - **Longer verify budget.** Verify's driver budget goes from 60 s to 120 s, and the CLI and MCP requests wait 125 s, so one reload fits even at its worst case (30 s navigation, 10 s proof, 10 s readiness). No binding was anchored to a blank answer: all 41 were checked for the empty-text digest. Browser contract 34, runtime generation 2026-09-23.13. ## Verification - Tests written first and seen failing: - verify reloads once and passes; - still blank after one reload gives `conversation_head_unrendered`; - an answer drawn with other text is still `conversation_head_changed` with no reload; - re-anchoring refuses a blank answer; - an exchange reloads once as a fenced stage, then sends; - a "Pro only" exchange gets both reloads; - still blank stops before anything is composed; - the broker retries the new code without re-anchoring; - a driver error in the new stage is a proven pre-Send failure. - `npm test`: 1417 tests, 1416 pass, 1 skipped. `npm run test:ego-monitor` 148/148. Receipt suite 16/16. ESLint clean on changed files. A3K fixture regenerated. - Codex review (read-only, `--base aab36cb`): no actionable regression. Its sandbox could not create temporary directories, so the suites above ran locally. - Codex review of the shared verify timeouts (read-only, last commit only): no actionable regression. ## Live check after install Ego Chat's broken tab is still open in Space 1. `ego-chat verify claude-code-live-check` should reload it once and pass.
Sign in to join this conversation.
No description provided.