devtools_print_crash_transcript.pdf and .md (full verbatim transcript of this conversation, both screenshots embedded). If this checkpoint is pasted into a fresh session, paste the transcript with it. Reply headers in the transcript (Claude: [08/10/2026--HH:MM:SS:mmm AEDT]) are the timestamps used below.Andrew keeps an independent, verbatim transcript of every AI conversation (AIs eventually paraphrase, embellish, censor or summarise despite instructions). His method is: open Chrome DevTools on claude.ai, paste a snippet that expands the chat so the browser's Print to PDF captures the whole conversation, then press Ctrl+P.
| # | Time (AEDT) | Attempt | Reported outcome |
|---|---|---|---|
| 1 | 03:57 | Andrew's original snippet: finds the largest overflow-y:auto div, hides all siblings up the ancestor chain, marks the chain data-pf, injects CSS forcing height:auto, overflow:visible, contain:none, content-visibility:visible. |
Crashes when the chat has a graphic (Andrew's report). |
| 2 | 03:57 | Reply 1: a count diagnostic, then a cleanup block (replace iframes/canvas/video with a placeholder, cap img/svg size), then the original snippet. | "that crashes too" (04:19). Diagnostic output returned: iframe 0, canvas 0, svg 1, img 0, video 0. |
| 3 | 04:20 | Reply 2: staged test (run only the hide-siblings half, then the style half without contain and content-visibility) plus a size diagnostic. |
Staged test result not reported. A screenshot of the size diagnostic came back (04:35): only page furniture, i.e. the 32x32 Claude "Spark" logo svg, a hidden analytics iframe (isolated-segment.html, display:none) and a hidden 1x1 about:blank iframe. |
| 4 | 04:35 | Reply 3: refined diagnostic listing only elements larger than 100x100. | Andrew: it "only just crashed a few moments ago", i.e. the crash also happened in a chat with no content graphic (implied: the Ship of Fools chat). |
| 5 | 04:37 | Reply 4: stop altering the live page; copy the scroller's innerHTML plus the page stylesheets into a new window and print that. |
No crash, but the print preview showed only one line at the top. |
| 6 | 04:43 | Reply 5: same new-window idea, but fetch the stylesheet text, neutralise every @media print, and reset inline position/transform/height in the copy. Built to tell print-CSS apart from positioning as the cause. |
Not reported. Andrew replied with frustration and asked for a quick one-fits-all fix. |
| 7 | 04:44 | Reply 6: plain-text fallback, copies sc.innerText into a <pre> in a new window. |
Not reported. Andrew hard-refreshed (Ctrl+F5) and proposed stripping or greying the graphics. |
| 8 | 05:23 | Reply 7: block that hides every graphic inside the chat (leaving a [graphic omitted] marker), to be pasted before "the old way". |
Andrew's version "displays the graphics again". He pasted his own three-part script (strip block, an overflow loop over every element, an @media print style). |
| 9 | 05:46 | Reply 8: single script, graphics hidden by an injected stylesheet rule so a page redraw cannot bring them back. | Andrew: "3 scripts, actually". |
| 10 | 05:46 | Reply 9: final script merging all three of his parts plus the stylesheet rule (section 3). | Not yet reported. |
| 11 | 06:12 to 06:18 | Transcript PDF and MD built and delivered. | Delivered. |
Observed (from Andrew's DevTools output):
about:blank).Uncaught TypeError ... reading 'startTime' in the console comes from the page's own bundled code (reportAllChanges, web-vitals style), not from the snippets. This is a judgement from the stack trace, not tested.Hypotheses, not verified:
height:auto / overflow:visible on the whole ancestor chain while the page's scripts keep running can set up a measure-and-grow loop (the chat list re-measures as the container grows). This was offered as the likely cause of the crash.@media print style, not the very first snippet. Reply 7 assumed the first snippet; his later paste suggests otherwise.Known good:
Proposal pending: the final script in section 3. Expected effect: all graphics inside the chat hidden, [graphic omitted] markers shown where they were, every container expanded, print preview showing the full conversation. Not yet confirmed.
| Risk | Detail |
|---|---|
| Tab crash again | The final script still runs a loop over document.querySelectorAll('*') that forces overflow/height on every element, the same class of layout forcing suspected earlier. It could crash on long chats. Cost: tab only, nothing is lost. |
| Wrong region picked | The scroller is "the largest overflow-y:auto div by scrollHeight". If another element wins (sidebar, a scrolling code block), the wrong region is tagged. If none matches, root is undefined and the script throws a TypeError. |
| Order dependence | The scroller must be found before the loop, because the loop sets overflow:visible everywhere and would stop it being found. The script already does this; do not reorder. |
| Graphics not caught | Hiding is by selector: iframe, canvas, video, object, embed, img, svg (svg inside a button or a is kept on purpose, to leave icons alone). A graphic drawn another way (CSS background, shadow DOM, an svg wrapped in a link or button) would still show. |
| Markers unreliable | [graphic omitted] markers are inserted by script and may be removed if the page redraws. The stylesheet rule hides the graphic regardless. |
| Print preview still truncated | The cause of the one-line preview is unresolved (print CSS vs positioning). The final script sets @media print overrides for overflow/height but does not disable the page's other print rules. |
| Print only captures what is rendered | If old messages are not in the DOM, they will not print. This is the main limit of the whole snippet approach for the "verbatim" goal. |
| Transcript made here is not independent | The PDF/MD in this conversation were produced from this session's own context, not from the page. Structure was checked (20 turns, balanced code fences, 2 embedded images, no blank pages), but the wording was copied by the model. Andrew's own capture remains the authority. |
| Tool rows and saved preferences omitted | The "Get current Sydney time" tool rows and the saved-preferences text were left out of the transcript on purpose, since they are not chat messages. |
No repository is involved. The "code" is a console script. Diff of the final script against Andrew's last pasted version (user_script_U9.js to final_script_A10.js; timestamps in the diff header removed):
--- user_script_U9.js
+++ final_script_A10.js
@@ -1,5 +1,6 @@
{
const root = [...document.querySelectorAll('div')].filter(e => getComputedStyle(e).overflowY === 'auto' && e.scrollHeight > e.clientHeight).sort((a,b) => b.scrollHeight - a.scrollHeight)[0];
+ root.setAttribute('data-gx','1');
let hidden = 0;
root.querySelectorAll('iframe,canvas,video,object,embed,img,svg').forEach(e => {
if (e.closest('button,a,[role=button]')) return;
@@ -20,4 +21,4 @@
el.style.maxHeight = 'none';
}
});
-document.head.appendChild(Object.assign(document.createElement('style'),{textContent:'@media print{*{overflow:visible!important;height:auto!important;max-height:none!important}}'}))
+document.head.appendChild(Object.assign(document.createElement('style'),{textContent:'[data-gx] iframe,[data-gx] canvas,[data-gx] video,[data-gx] object,[data-gx] embed,[data-gx] img,[data-gx] svg:not(button svg):not(a svg){display:none!important}@media print{*{overflow:visible!important;height:auto!important;max-height:none!important}}'}))
Meaning of the two changes:
root.setAttribute('data-gx','1') tags the chat scroller so a stylesheet rule can target everything inside it.display:none!important for graphics under [data-gx], so a page redraw cannot bring them back. The existing per-element hiding and [graphic omitted] markers are kept as a backup.{
const root = [...document.querySelectorAll('div')].filter(e => getComputedStyle(e).overflowY === 'auto' && e.scrollHeight > e.clientHeight).sort((a,b) => b.scrollHeight - a.scrollHeight)[0];
root.setAttribute('data-gx','1');
let hidden = 0;
root.querySelectorAll('iframe,canvas,video,object,embed,img,svg').forEach(e => {
if (e.closest('button,a,[role=button]')) return;
if (e.parentElement && e.parentElement.closest('svg')) return;
const m = document.createElement('div');
m.textContent = '[graphic omitted]';
e.parentNode.insertBefore(m, e);
e.style.setProperty('display','none','important');
hidden++;
});
console.log('graphics hidden:', hidden);
}
document.querySelectorAll('*').forEach(el => {
const s = getComputedStyle(el);
if (s.overflowY !== 'visible' || s.position === 'fixed' || el.scrollHeight > el.clientHeight) {
el.style.overflow = 'visible';
el.style.height = 'auto';
el.style.maxHeight = 'none';
}
});
document.head.appendChild(Object.assign(document.createElement('style'),{textContent:'[data-gx] iframe,[data-gx] canvas,[data-gx] video,[data-gx] object,[data-gx] embed,[data-gx] img,[data-gx] svg:not(button svg):not(a svg){display:none!important}@media print{*{overflow:visible!important;height:auto!important;max-height:none!important}}'}))
The console prints graphics hidden: N. N = 0 on a chat that has graphics means the selector missed them.
const sc = [...document.querySelectorAll('div')].filter(e => getComputedStyle(e).overflowY === 'auto' && e.scrollHeight > e.clientHeight).sort((a,b) => b.scrollHeight - a.scrollHeight)[0];
const w = window.open('', '_blank');
w.document.write('<!doctype html><meta charset="utf-8"><title>chat</title><pre style="white-space:pre-wrap;font:14px/1.5 Georgia,serif;max-width:800px;margin:auto"></pre>');
w.document.close();
w.document.querySelector('pre').textContent = sc.innerText;
[...document.querySelectorAll('svg,iframe,canvas,img,video')].forEach(e => { const r = e.getBoundingClientRect(); if (r.width > 100 && r.height > 100) console.log(e.tagName, Math.round(r.width) + 'x' + Math.round(r.height), e); });
Other variants (staged test, new-window copy, fetch-and-neutralise-print-CSS) are in the transcript, in the replies stamped 04:20:14, 04:37:10 and 04:43:06.
querySelectorAll('*') loop. Run the staged test from the reply stamped 04:20:14 (hide siblings only, then the style half without contain and content-visibility) to find which stage kills the tab.devtools_print_crash_transcript.pdf (8 pages, A4, claude.ai Print-to-PDF style: no speaker labels, Andrew's turns indented right, Claude full width, inline code chips, date plus "Claude" header, page numbers) and devtools_print_crash_transcript.md (self-contained, screenshots embedded, Andrew's messages in plain text blocks).devtools_print_crash_transcript_2.md / .pdf), never overwriting the first./home/claude/transcript/ containing transcript_src.md, build_transcript.py, images/, user_script_U9.js, final_script_A10.js.checkpoint.md.