Widen the mirror-vs-PTY geometry check beyond bottomAnchor: a mismatched mirror may hand claude a false CLEAN #202

Description

@pseudoseed

Split out of #197 on the architect's instruction, because it changes live behaviour for harnesses
that work today and deserves its own review rather than riding along behind an opencode fix.

Background

#197 establishes that a PtySession's mirror is born at defaultSessionOptions() = 80x24 and is
only ever resized by a connected browser client. Measured on a live workspace, real agent
geometry is 60-84 rows; four sessions were sitting at exactly 80x24 in a running system. The
shellper's true geometry is already on the wire in WelcomeMessage.cols/.rows and discarded.

#197 fixes the mirror by adopting that geometry on attach, and adds a fact-based check
comparing the mirror against the PTY's real size. That check is deliberately scoped to
bottomAnchor profiles (opencode only), so claude, codex and agy are provably byte-identical
before and after.

The ask

Consider widening the fact-based mirror-vs-PTY check to every harness.

The builder's argument, which the architect judged stronger than it was pitched:

A mismatched mirror can in principle hand claude a false CLEAN.

That is the dangerous direction. The render gate exists to stop a message being typed into a
screen that is not a verified-empty prompt. Its failure modes are not symmetric:

  • False hold — the gate cannot verify a clean prompt that is actually clean. Costs minutes of
    delayed mail. This is the opencode failure opencode builders are not reliably reachable — 4 fixes on our side of the line #195 documents.
  • False CLEAN — the gate reports a verified-empty prompt when the real screen is not one.
    Delivers into a live turn, onto a half-typed line, or into a dialog. This is the failure the
    whole subsystem was built to prevent.

A mirror smaller than the real screen shows the gate a subset of what the agent painted. For a
top-anchored composer that subset can plausibly look clean while the real screen is not.

Why it was not done in #197

Correctly, and it should stay that way there. It is a live behaviour change for harnesses that
deliver reliably today: a claude session with a mismatched mirror that delivers now would start
holding. And — the reason it needs its own issue rather than a follow-up line — no fixture would
catch it
, so a green render-gate suite is not evidence either way. "Fixtures green" would have
been a misleading proof.

What this issue needs to establish

  1. Is a false CLEAN actually reachable for a top-anchored profile under a shorter mirror, or
    only theoretically? Construct it from real captures at a real mismatch (80x24 mirror against a
    110x32 agent is the measured field shape) rather than reasoning about it.
  2. If reachable, widen the check and accept the new holds as correct.
  3. If not reachable, say so with the evidence and close — "we looked and it cannot happen" is a
    result worth having on record.
  4. Whichever way it goes, the check must report which direction it detected. opencode render-gate profile no longer matches: capture current frames, then fix, then guard against drift #197's finding
    was that a rows-clip was reported as no-composer-marker — "my mirror is the wrong height"
    spelled as "this app has no composer". Do not reintroduce that one level up.

Related: #197 (the fix this splits from), #195 (parent), #199.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/towerTower, afx, terminals, messaging

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
       blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
      }
      } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
      })();
      (function(){
      try {
      var __m = "github.com";
      var __re = new RegExp('^' + "github\\.com" + '
      
      Skip to content

      Widen the mirror-vs-PTY geometry check beyond bottomAnchor: a mismatched mirror may hand claude a false CLEAN #202

      Description

      @pseudoseed

      Split out of #197 on the architect's instruction, because it changes live behaviour for harnesses
      that work today and deserves its own review rather than riding along behind an opencode fix.

      Background

      #197 establishes that a PtySession's mirror is born at defaultSessionOptions() = 80x24 and is
      only ever resized by a connected browser client. Measured on a live workspace, real agent
      geometry is 60-84 rows; four sessions were sitting at exactly 80x24 in a running system. The
      shellper's true geometry is already on the wire in WelcomeMessage.cols/.rows and discarded.

      #197 fixes the mirror by adopting that geometry on attach, and adds a fact-based check
      comparing the mirror against the PTY's real size. That check is deliberately scoped to
      bottomAnchor profiles (opencode only), so claude, codex and agy are provably byte-identical
      before and after.

      The ask

      Consider widening the fact-based mirror-vs-PTY check to every harness.

      The builder's argument, which the architect judged stronger than it was pitched:

      A mismatched mirror can in principle hand claude a false CLEAN.

      That is the dangerous direction. The render gate exists to stop a message being typed into a
      screen that is not a verified-empty prompt. Its failure modes are not symmetric:

      • False hold — the gate cannot verify a clean prompt that is actually clean. Costs minutes of
        delayed mail. This is the opencode failure opencode builders are not reliably reachable — 4 fixes on our side of the line #195 documents.
      • False CLEAN — the gate reports a verified-empty prompt when the real screen is not one.
        Delivers into a live turn, onto a half-typed line, or into a dialog. This is the failure the
        whole subsystem was built to prevent.

      A mirror smaller than the real screen shows the gate a subset of what the agent painted. For a
      top-anchored composer that subset can plausibly look clean while the real screen is not.

      Why it was not done in #197

      Correctly, and it should stay that way there. It is a live behaviour change for harnesses that
      deliver reliably today: a claude session with a mismatched mirror that delivers now would start
      holding. And — the reason it needs its own issue rather than a follow-up line — no fixture would
      catch it
      , so a green render-gate suite is not evidence either way. "Fixtures green" would have
      been a misleading proof.

      What this issue needs to establish

      1. Is a false CLEAN actually reachable for a top-anchored profile under a shorter mirror, or
        only theoretically? Construct it from real captures at a real mismatch (80x24 mirror against a
        110x32 agent is the measured field shape) rather than reasoning about it.
      2. If reachable, widen the check and accept the new holds as correct.
      3. If not reachable, say so with the evidence and close — "we looked and it cannot happen" is a
        result worth having on record.
      4. Whichever way it goes, the check must report which direction it detected. opencode render-gate profile no longer matches: capture current frames, then fix, then guard against drift #197's finding
        was that a rows-clip was reported as no-composer-marker — "my mirror is the wrong height"
        spelled as "this app has no composer". Do not reintroduce that one level up.

      Related: #197 (the fix this splits from), #195 (parent), #199.

      Activity

      Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        area/towerTower, afx, terminals, messaging

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
          Skip to content

          Widen the mirror-vs-PTY geometry check beyond bottomAnchor: a mismatched mirror may hand claude a false CLEAN #202

          Description

          @pseudoseed

          Split out of #197 on the architect's instruction, because it changes live behaviour for harnesses
          that work today and deserves its own review rather than riding along behind an opencode fix.

          Background

          #197 establishes that a PtySession's mirror is born at defaultSessionOptions() = 80x24 and is
          only ever resized by a connected browser client. Measured on a live workspace, real agent
          geometry is 60-84 rows; four sessions were sitting at exactly 80x24 in a running system. The
          shellper's true geometry is already on the wire in WelcomeMessage.cols/.rows and discarded.

          #197 fixes the mirror by adopting that geometry on attach, and adds a fact-based check
          comparing the mirror against the PTY's real size. That check is deliberately scoped to
          bottomAnchor profiles (opencode only), so claude, codex and agy are provably byte-identical
          before and after.

          The ask

          Consider widening the fact-based mirror-vs-PTY check to every harness.

          The builder's argument, which the architect judged stronger than it was pitched:

          A mismatched mirror can in principle hand claude a false CLEAN.

          That is the dangerous direction. The render gate exists to stop a message being typed into a
          screen that is not a verified-empty prompt. Its failure modes are not symmetric:

          • False hold — the gate cannot verify a clean prompt that is actually clean. Costs minutes of
            delayed mail. This is the opencode failure opencode builders are not reliably reachable — 4 fixes on our side of the line #195 documents.
          • False CLEAN — the gate reports a verified-empty prompt when the real screen is not one.
            Delivers into a live turn, onto a half-typed line, or into a dialog. This is the failure the
            whole subsystem was built to prevent.

          A mirror smaller than the real screen shows the gate a subset of what the agent painted. For a
          top-anchored composer that subset can plausibly look clean while the real screen is not.

          Why it was not done in #197

          Correctly, and it should stay that way there. It is a live behaviour change for harnesses that
          deliver reliably today: a claude session with a mismatched mirror that delivers now would start
          holding. And — the reason it needs its own issue rather than a follow-up line — no fixture would
          catch it
          , so a green render-gate suite is not evidence either way. "Fixtures green" would have
          been a misleading proof.

          What this issue needs to establish

          1. Is a false CLEAN actually reachable for a top-anchored profile under a shorter mirror, or
            only theoretically? Construct it from real captures at a real mismatch (80x24 mirror against a
            110x32 agent is the measured field shape) rather than reasoning about it.
          2. If reachable, widen the check and accept the new holds as correct.
          3. If not reachable, say so with the evidence and close — "we looked and it cannot happen" is a
            result worth having on record.
          4. Whichever way it goes, the check must report which direction it detected. opencode render-gate profile no longer matches: capture current frames, then fix, then guard against drift #197's finding
            was that a rows-clip was reported as no-composer-marker — "my mirror is the wrong height"
            spelled as "this app has no composer". Do not reintroduce that one level up.

          Related: #197 (the fix this splits from), #195 (parent), #199.

          Activity

          Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            area/towerTower, afx, terminals, messaging

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              Widen the mirror-vs-PTY geometry check beyond bottomAnchor: a mismatched mirror may hand claude a false CLEAN #202

              Description

              @pseudoseed

              Split out of #197 on the architect's instruction, because it changes live behaviour for harnesses
              that work today and deserves its own review rather than riding along behind an opencode fix.

              Background

              #197 establishes that a PtySession's mirror is born at defaultSessionOptions() = 80x24 and is
              only ever resized by a connected browser client. Measured on a live workspace, real agent
              geometry is 60-84 rows; four sessions were sitting at exactly 80x24 in a running system. The
              shellper's true geometry is already on the wire in WelcomeMessage.cols/.rows and discarded.

              #197 fixes the mirror by adopting that geometry on attach, and adds a fact-based check
              comparing the mirror against the PTY's real size. That check is deliberately scoped to
              bottomAnchor profiles (opencode only), so claude, codex and agy are provably byte-identical
              before and after.

              The ask

              Consider widening the fact-based mirror-vs-PTY check to every harness.

              The builder's argument, which the architect judged stronger than it was pitched:

              A mismatched mirror can in principle hand claude a false CLEAN.

              That is the dangerous direction. The render gate exists to stop a message being typed into a
              screen that is not a verified-empty prompt. Its failure modes are not symmetric:

              • False hold — the gate cannot verify a clean prompt that is actually clean. Costs minutes of
                delayed mail. This is the opencode failure opencode builders are not reliably reachable — 4 fixes on our side of the line #195 documents.
              • False CLEAN — the gate reports a verified-empty prompt when the real screen is not one.
                Delivers into a live turn, onto a half-typed line, or into a dialog. This is the failure the
                whole subsystem was built to prevent.

              A mirror smaller than the real screen shows the gate a subset of what the agent painted. For a
              top-anchored composer that subset can plausibly look clean while the real screen is not.

              Why it was not done in #197

              Correctly, and it should stay that way there. It is a live behaviour change for harnesses that
              deliver reliably today: a claude session with a mismatched mirror that delivers now would start
              holding. And — the reason it needs its own issue rather than a follow-up line — no fixture would
              catch it
              , so a green render-gate suite is not evidence either way. "Fixtures green" would have
              been a misleading proof.

              What this issue needs to establish

              1. Is a false CLEAN actually reachable for a top-anchored profile under a shorter mirror, or
                only theoretically? Construct it from real captures at a real mismatch (80x24 mirror against a
                110x32 agent is the measured field shape) rather than reasoning about it.
              2. If reachable, widen the check and accept the new holds as correct.
              3. If not reachable, say so with the evidence and close — "we looked and it cannot happen" is a
                result worth having on record.
              4. Whichever way it goes, the check must report which direction it detected. opencode render-gate profile no longer matches: capture current frames, then fix, then guard against drift #197's finding
                was that a rows-clip was reported as no-composer-marker — "my mirror is the wrong height"
                spelled as "this app has no composer". Do not reintroduce that one level up.

              Related: #197 (the fix this splits from), #195 (parent), #199.

              Activity

              Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                area/towerTower, afx, terminals, messaging

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
                  Skip to content

                  Widen the mirror-vs-PTY geometry check beyond bottomAnchor: a mismatched mirror may hand claude a false CLEAN #202

                  Description

                  @pseudoseed

                  Split out of #197 on the architect's instruction, because it changes live behaviour for harnesses
                  that work today and deserves its own review rather than riding along behind an opencode fix.

                  Background

                  #197 establishes that a PtySession's mirror is born at defaultSessionOptions() = 80x24 and is
                  only ever resized by a connected browser client. Measured on a live workspace, real agent
                  geometry is 60-84 rows; four sessions were sitting at exactly 80x24 in a running system. The
                  shellper's true geometry is already on the wire in WelcomeMessage.cols/.rows and discarded.

                  #197 fixes the mirror by adopting that geometry on attach, and adds a fact-based check
                  comparing the mirror against the PTY's real size. That check is deliberately scoped to
                  bottomAnchor profiles (opencode only), so claude, codex and agy are provably byte-identical
                  before and after.

                  The ask

                  Consider widening the fact-based mirror-vs-PTY check to every harness.

                  The builder's argument, which the architect judged stronger than it was pitched:

                  A mismatched mirror can in principle hand claude a false CLEAN.

                  That is the dangerous direction. The render gate exists to stop a message being typed into a
                  screen that is not a verified-empty prompt. Its failure modes are not symmetric:

                  • False hold — the gate cannot verify a clean prompt that is actually clean. Costs minutes of
                    delayed mail. This is the opencode failure opencode builders are not reliably reachable — 4 fixes on our side of the line #195 documents.
                  • False CLEAN — the gate reports a verified-empty prompt when the real screen is not one.
                    Delivers into a live turn, onto a half-typed line, or into a dialog. This is the failure the
                    whole subsystem was built to prevent.

                  A mirror smaller than the real screen shows the gate a subset of what the agent painted. For a
                  top-anchored composer that subset can plausibly look clean while the real screen is not.

                  Why it was not done in #197

                  Correctly, and it should stay that way there. It is a live behaviour change for harnesses that
                  deliver reliably today: a claude session with a mismatched mirror that delivers now would start
                  holding. And — the reason it needs its own issue rather than a follow-up line — no fixture would
                  catch it
                  , so a green render-gate suite is not evidence either way. "Fixtures green" would have
                  been a misleading proof.

                  What this issue needs to establish

                  1. Is a false CLEAN actually reachable for a top-anchored profile under a shorter mirror, or
                    only theoretically? Construct it from real captures at a real mismatch (80x24 mirror against a
                    110x32 agent is the measured field shape) rather than reasoning about it.
                  2. If reachable, widen the check and accept the new holds as correct.
                  3. If not reachable, say so with the evidence and close — "we looked and it cannot happen" is a
                    result worth having on record.
                  4. Whichever way it goes, the check must report which direction it detected. opencode render-gate profile no longer matches: capture current frames, then fix, then guard against drift #197's finding
                    was that a rows-clip was reported as no-composer-marker — "my mirror is the wrong height"
                    spelled as "this app has no composer". Do not reintroduce that one level up.

                  Related: #197 (the fix this splits from), #195 (parent), #199.

                  Activity

                  Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    area/towerTower, afx, terminals, messaging

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                      Skip to content

                      Widen the mirror-vs-PTY geometry check beyond bottomAnchor: a mismatched mirror may hand claude a false CLEAN #202

                      Description

                      @pseudoseed

                      Split out of #197 on the architect's instruction, because it changes live behaviour for harnesses
                      that work today and deserves its own review rather than riding along behind an opencode fix.

                      Background

                      #197 establishes that a PtySession's mirror is born at defaultSessionOptions() = 80x24 and is
                      only ever resized by a connected browser client. Measured on a live workspace, real agent
                      geometry is 60-84 rows; four sessions were sitting at exactly 80x24 in a running system. The
                      shellper's true geometry is already on the wire in WelcomeMessage.cols/.rows and discarded.

                      #197 fixes the mirror by adopting that geometry on attach, and adds a fact-based check
                      comparing the mirror against the PTY's real size. That check is deliberately scoped to
                      bottomAnchor profiles (opencode only), so claude, codex and agy are provably byte-identical
                      before and after.

                      The ask

                      Consider widening the fact-based mirror-vs-PTY check to every harness.

                      The builder's argument, which the architect judged stronger than it was pitched:

                      A mismatched mirror can in principle hand claude a false CLEAN.

                      That is the dangerous direction. The render gate exists to stop a message being typed into a
                      screen that is not a verified-empty prompt. Its failure modes are not symmetric:

                      • False hold — the gate cannot verify a clean prompt that is actually clean. Costs minutes of
                        delayed mail. This is the opencode failure opencode builders are not reliably reachable — 4 fixes on our side of the line #195 documents.
                      • False CLEAN — the gate reports a verified-empty prompt when the real screen is not one.
                        Delivers into a live turn, onto a half-typed line, or into a dialog. This is the failure the
                        whole subsystem was built to prevent.

                      A mirror smaller than the real screen shows the gate a subset of what the agent painted. For a
                      top-anchored composer that subset can plausibly look clean while the real screen is not.

                      Why it was not done in #197

                      Correctly, and it should stay that way there. It is a live behaviour change for harnesses that
                      deliver reliably today: a claude session with a mismatched mirror that delivers now would start
                      holding. And — the reason it needs its own issue rather than a follow-up line — no fixture would
                      catch it
                      , so a green render-gate suite is not evidence either way. "Fixtures green" would have
                      been a misleading proof.

                      What this issue needs to establish

                      1. Is a false CLEAN actually reachable for a top-anchored profile under a shorter mirror, or
                        only theoretically? Construct it from real captures at a real mismatch (80x24 mirror against a
                        110x32 agent is the measured field shape) rather than reasoning about it.
                      2. If reachable, widen the check and accept the new holds as correct.
                      3. If not reachable, say so with the evidence and close — "we looked and it cannot happen" is a
                        result worth having on record.
                      4. Whichever way it goes, the check must report which direction it detected. opencode render-gate profile no longer matches: capture current frames, then fix, then guard against drift #197's finding
                        was that a rows-clip was reported as no-composer-marker — "my mirror is the wrong height"
                        spelled as "this app has no composer". Do not reintroduce that one level up.

                      Related: #197 (the fix this splits from), #195 (parent), #199.

                      Activity

                      Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        area/towerTower, afx, terminals, messaging

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                          Skip to content

                          Widen the mirror-vs-PTY geometry check beyond bottomAnchor: a mismatched mirror may hand claude a false CLEAN #202

                          Description

                          @pseudoseed

                          Split out of #197 on the architect's instruction, because it changes live behaviour for harnesses
                          that work today and deserves its own review rather than riding along behind an opencode fix.

                          Background

                          #197 establishes that a PtySession's mirror is born at defaultSessionOptions() = 80x24 and is
                          only ever resized by a connected browser client. Measured on a live workspace, real agent
                          geometry is 60-84 rows; four sessions were sitting at exactly 80x24 in a running system. The
                          shellper's true geometry is already on the wire in WelcomeMessage.cols/.rows and discarded.

                          #197 fixes the mirror by adopting that geometry on attach, and adds a fact-based check
                          comparing the mirror against the PTY's real size. That check is deliberately scoped to
                          bottomAnchor profiles (opencode only), so claude, codex and agy are provably byte-identical
                          before and after.

                          The ask

                          Consider widening the fact-based mirror-vs-PTY check to every harness.

                          The builder's argument, which the architect judged stronger than it was pitched:

                          A mismatched mirror can in principle hand claude a false CLEAN.

                          That is the dangerous direction. The render gate exists to stop a message being typed into a
                          screen that is not a verified-empty prompt. Its failure modes are not symmetric:

                          • False hold — the gate cannot verify a clean prompt that is actually clean. Costs minutes of
                            delayed mail. This is the opencode failure opencode builders are not reliably reachable — 4 fixes on our side of the line #195 documents.
                          • False CLEAN — the gate reports a verified-empty prompt when the real screen is not one.
                            Delivers into a live turn, onto a half-typed line, or into a dialog. This is the failure the
                            whole subsystem was built to prevent.

                          A mirror smaller than the real screen shows the gate a subset of what the agent painted. For a
                          top-anchored composer that subset can plausibly look clean while the real screen is not.

                          Why it was not done in #197

                          Correctly, and it should stay that way there. It is a live behaviour change for harnesses that
                          deliver reliably today: a claude session with a mismatched mirror that delivers now would start
                          holding. And — the reason it needs its own issue rather than a follow-up line — no fixture would
                          catch it
                          , so a green render-gate suite is not evidence either way. "Fixtures green" would have
                          been a misleading proof.

                          What this issue needs to establish

                          1. Is a false CLEAN actually reachable for a top-anchored profile under a shorter mirror, or
                            only theoretically? Construct it from real captures at a real mismatch (80x24 mirror against a
                            110x32 agent is the measured field shape) rather than reasoning about it.
                          2. If reachable, widen the check and accept the new holds as correct.
                          3. If not reachable, say so with the evidence and close — "we looked and it cannot happen" is a
                            result worth having on record.
                          4. Whichever way it goes, the check must report which direction it detected. opencode render-gate profile no longer matches: capture current frames, then fix, then guard against drift #197's finding
                            was that a rows-clip was reported as no-composer-marker — "my mirror is the wrong height"
                            spelled as "this app has no composer". Do not reintroduce that one level up.

                          Related: #197 (the fix this splits from), #195 (parent), #199.

                          Activity

                          Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            area/towerTower, afx, terminals, messaging

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                              Skip to content

                              Widen the mirror-vs-PTY geometry check beyond bottomAnchor: a mismatched mirror may hand claude a false CLEAN #202

                              Description

                              @pseudoseed

                              Split out of #197 on the architect's instruction, because it changes live behaviour for harnesses
                              that work today and deserves its own review rather than riding along behind an opencode fix.

                              Background

                              #197 establishes that a PtySession's mirror is born at defaultSessionOptions() = 80x24 and is
                              only ever resized by a connected browser client. Measured on a live workspace, real agent
                              geometry is 60-84 rows; four sessions were sitting at exactly 80x24 in a running system. The
                              shellper's true geometry is already on the wire in WelcomeMessage.cols/.rows and discarded.

                              #197 fixes the mirror by adopting that geometry on attach, and adds a fact-based check
                              comparing the mirror against the PTY's real size. That check is deliberately scoped to
                              bottomAnchor profiles (opencode only), so claude, codex and agy are provably byte-identical
                              before and after.

                              The ask

                              Consider widening the fact-based mirror-vs-PTY check to every harness.

                              The builder's argument, which the architect judged stronger than it was pitched:

                              A mismatched mirror can in principle hand claude a false CLEAN.

                              That is the dangerous direction. The render gate exists to stop a message being typed into a
                              screen that is not a verified-empty prompt. Its failure modes are not symmetric:

                              • False hold — the gate cannot verify a clean prompt that is actually clean. Costs minutes of
                                delayed mail. This is the opencode failure opencode builders are not reliably reachable — 4 fixes on our side of the line #195 documents.
                              • False CLEAN — the gate reports a verified-empty prompt when the real screen is not one.
                                Delivers into a live turn, onto a half-typed line, or into a dialog. This is the failure the
                                whole subsystem was built to prevent.

                              A mirror smaller than the real screen shows the gate a subset of what the agent painted. For a
                              top-anchored composer that subset can plausibly look clean while the real screen is not.

                              Why it was not done in #197

                              Correctly, and it should stay that way there. It is a live behaviour change for harnesses that
                              deliver reliably today: a claude session with a mismatched mirror that delivers now would start
                              holding. And — the reason it needs its own issue rather than a follow-up line — no fixture would
                              catch it
                              , so a green render-gate suite is not evidence either way. "Fixtures green" would have
                              been a misleading proof.

                              What this issue needs to establish

                              1. Is a false CLEAN actually reachable for a top-anchored profile under a shorter mirror, or
                                only theoretically? Construct it from real captures at a real mismatch (80x24 mirror against a
                                110x32 agent is the measured field shape) rather than reasoning about it.
                              2. If reachable, widen the check and accept the new holds as correct.
                              3. If not reachable, say so with the evidence and close — "we looked and it cannot happen" is a
                                result worth having on record.
                              4. Whichever way it goes, the check must report which direction it detected. opencode render-gate profile no longer matches: capture current frames, then fix, then guard against drift #197's finding
                                was that a rows-clip was reported as no-composer-marker — "my mirror is the wrong height"
                                spelled as "this app has no composer". Do not reintroduce that one level up.

                              Related: #197 (the fix this splits from), #195 (parent), #199.

                              Activity

                              Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                area/towerTower, afx, terminals, messaging

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions