Skip to content

fix: preserve Pi stock rendering and stabilize remote provisioning - #10

Merged
MrGTV-love merged 10 commits into
mainfrom
fm/fm-pi-render-drift
Oct 5, 2026
Merged

MrGTV-love merged 10 commits into
mainfrom
fm/fm-pi-render-drift

Conversation

@MrGTV-love

@MrGTV-love MrGTV-love commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Intent

Fork main CI (MrGTV-love/firstmate) now fails two tests in the "Behavior portable serial" shards 2 and 4 on every PR and on main itself: "rendered export DOM violated the Calm conversation boundary" and "Pi outcomes rendering consumers must preserve stock behavior ... Error: Calm-off ToolExecutionComponent rendering differs from Pi stock". Main passed them at 2026-09-29 06:05 (run 36529338484); fm-subagent-guard-fix reproduced both on current main, so the cause is outside our changes (most likely a newer Pi release). Shards 7 and 8 also failed once on PRs 6 and 7 as flakes (remote seed did not provision the route under test). These red checks block merging #6 and #7, and will block the launcher and monitor fixes. The captain does not merge red PRs and wants no non-valuable friction.

What Changed

  • Delegate supervision-tool rendering to Pi’s stock ToolExecutionComponent, preserving argument previews, result formatting, expansion, and error styling while retaining Calm hiding and stock export fallback.
  • Update Pi regression fixtures for newer HTML renderer interfaces, browser-visible export boundaries and hidden-message toggles, persistent reload completion, regular-mode scrollback, and wrapped export confirmations; refresh compatibility documentation and ignore runtime cache directories.
  • Provision remote homes with git clone --no-local to avoid source-repack races, add coverage for independent cloned objects, and expose provisioning and inheritance failure output.

Risk Assessment

✅ Low: The changes are bounded compatibility fixes that delegate formatting to Pi, preserve existing execution and visibility controls, and avoid Git's local object-copying race; no material source defect or unnecessary component was substantiated.

Testing

After correcting disposable tmux setup issues, the original 64-case Calm/branch acceptance passed on both Pi versions. Live Pi tool execution and Chromium exports confirmed stock previews, expansion, error rendering, Calm hiding/restoration, and export boundaries; real Git provisioning passed concurrent publication, foreign-home refusal, and source-repack checks. Screenshots, HTML, terminal captures, and provisioning output were preserved, and disposable material was removed. No broad suite, lint, or static analysis was run.

  • Live validation: ✅ go - 8 of 8 scenarios driven live against the product
Scenario Result Live Evidence
Read supervision outcomes with stock argument previews and expand the full result ✅ pass live branch-live/pi102-stock-collapsed.txt and pi099-stock-collapsed.txt; corresponding stock-expanded captures.
Submit invalid and unowned acknowledgements without losing stock error presentation ✅ pass live branch-live/pi102-browser-errors.png, pi099-browser-errors.png, and native exported toolResult data.
Toggle Calm around supervision tools and export without leaving hidden rows visible ✅ pass live branch-live/pi102- and pi099-calm-hidden.txt, calm-after-export.txt, calm-restored.txt, and actual HTML exports.
Export a Calm conversation while retaining genuine turns and stock operational history ✅ pass live Pi 1.0.2 and 0.99.0 exported conversation screenshots, generated HTML, and browser-export-observations.json.
Explicitly reveal hidden export history, then restore the conversation boundary ✅ pass live Both versions' export-hidden-revealed.png screenshots and browser-export-observations.json.
Reload and resume Calm without changing regular replay or hidden-block geometry ✅ pass live Original live Calm acceptance on both versions, including native /reload, expansion and restart; preserved restarted.txt and restored.txt captures.
Provision a remote home while the source repository repacks ✅ pass live Provision-only executable scenario; remote-repack-provision.out, remote-provisioned-home.txt, and destination fsck before and after source-object removal.
Race provisioning with another attempt, cleanup and a foreign destination ✅ pass live Provision-only executable scenarios and remote-appeared-provision.out.

Pi 1.0.2 exported conversation and stock tool output

Evidence: Native supervision tool argument previews and collapsed expansion hint

Source: Native supervision tool argument previews and collapsed expansion hint


 ▀▀█  v1.0.2
 █▀ █ escape interrupt · ctrl+c/ctrl+d clear/exit · / commands · ! bash · ctrl+o more
 Press ctrl+o to show full startup help and loaded resources.

 Pi can explain its own features and look up its docs. Ask it how to use or extend Pi.

[Extensions]
  fm-branch-supervision.ts, fm-calm.ts, provider.ts


 Warning: fd not found. Offline mode enabled, skipping download.
 Warning: ripgrep not found. Offline mode enabled, skipping download.

 This project is not trusted. Project .pi resources and packages are ignored. Use /trust to save a trust decision, then
 restart pi.


 Exercise branch renderers with the deterministic local fixture.



 fm_branch_outcomes recent=14
 {"seq": 1, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-01:
 LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LIN
 E-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-L
 INE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG
 -LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-LONG-LINE-", "silent": false,
 "statusEndpoint": 0, "statusIdent": ""}
 {"seq": 2, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-02: ordinary result row confirms multiline stock expansion and durable read path.", "silent":
 false, "statusEndpoint": 0, "statusIdent": ""}
 {"seq": 3, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-03: ordinary result row confirms multiline stock expansion and durable read path.", "silent":
 false, "statusEndpoint": 0, "statusIdent": ""}
 {"seq": 4, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-04: ordinary result row confirms multiline stock expansion and durable read path.", "silent":
 false, "statusEndpoint": 0, "statusIdent": ""}
 {"seq": 5, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-05: ordinary result row confirms multiline stock expansion and durable read path.", "silent":
 false, "statusEndpoint": 0, "statusIdent": ""}
 {"seq": 6, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-06: ordinary result row confirms multiline stock expansion and durable read path.", "silent":
 false, "statusEndpoint": 0, "statusIdent": ""}
 {"seq": 7, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-07: ordinary result row confirms multiline stock expansion and durable read path.", "silent":
 false, "statusEndpoint": 0, "statusIdent": ""}
 {"seq": 8, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-08: ordinary result row confirms multiline stock expansion and durable read path.", "silent":
 false, "statusEndpoint": 0, "statusIdent": ""}
 {"seq": 9, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-09: ordinary result row confirms multiline stock expansion and durable read path.", "silent":
 false, "statusEndpoint": 0, "statusIdent": ""}
 {"seq": 10, "epoch": 1791072000, "task": "branch-render-lab", "wake": "disposable-fixture-only", "verdict": "routine",
 "summary": "OUTCOME-10: ordinary result row confirms multiline stock expansion and durable read path.", "silent":
 false, "statusEndpoint": 0, "statusIdent": ""}
 ... (4 more lines, ctrl+o to expand)



 fm_branch_processed through=0
 acknowledgement refused: through must be a positive outcome sequence number



 fm_branch_processed through=999
 acknowledgement refused: this session does not own the fleet lock


 Branch renderer lab complete. Actual registered tools executed; the provider is a deterministic local fixture, not a
 live LLM.























────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
~/.no-mistakes/worktrees/32d18ed9638d/01M44P33S4FCMC3A82HAN56PSW (detached)
2.9%/100k (auto)                                                                                           deterministic
Evidence: Calm hides supervision rows after export while preserving confirmation

Source: Calm hides supervision rows after export while preserving confirmation


 ▀▀█  v1.0.2
 █▀ █ escape to interrupt
 ctrl+c to clear
 ctrl+c twice to exit
 ctrl+d to exit (empty)
 ctrl+z to suspend
 ctrl+k to delete to end
 shift+tab to cycle thinking level
 ctrl+p/shift+ctrl+p to cycle models
 ctrl+l to select model
 ctrl+o to expand tools
 ctrl+t to expand thinking
 ctrl+g for external editor
 / for commands
 ! to run bash
 !! to run bash (no context)
 option+enter to queue follow-up
 option+up to edit all queued messages
 ctrl+v to paste files on macOS, images, or text
 drop files to attach

 Pi can explain its own features and look up its docs. Ask it how to use or extend Pi.

[Extensions]
  path

~/.no-mistakes/worktrees/32d18ed9638d/01M44P33S4FCMC3A82HAN56PSW/.gate-test-lab/branch-live/provide
r.ts

~/.no-mistakes/worktrees/32d18ed9638d/01M44P33S4FCMC3A82HAN56PSW/.pi/extensions/fm-branch-supervisi
on.ts
    ~/.no-mistakes/worktrees/32d18ed9638d/01M44P33S4FCMC3A82HAN56PSW/.pi/extensions/fm-calm.ts


 Warning: fd not found. Offline mode enabled, skipping download.
 Warning: ripgrep not found. Offline mode enabled, skipping download.

 This project is not trusted. Project .pi resources and packages are ignored. Use /trust to save a trust decision, then
 restart pi.


 Exercise branch renderers with the deterministic local fixture.


 Branch renderer lab complete. Actual registered tools executed; the provider is a deterministic local fixture, not a
 live LLM.

 Session exported to:
 ~/.no-mistakes/evidence/01M44P33S4FCMC3A82HAN56PSW/branch-live/pi102-calm-stock-export.html













































────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
~/.no-mistakes/worktrees/32d18ed9638d/01M44P33S4FCMC3A82HAN56PSW (detached)
2.9%/100k (auto)                                                                                           deterministic
Evidence: Actual native supervision HTML export

Source: Actual native supervision HTML export

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Session Export</title>
  <style>
    :root {
      --accent: #800080;
      --borderAccent: #800080;
      --customMessageLabel: #800080;
      --mdCode: #800080;
      --mdListBullet: #800080;
      --syntaxType: #800080;
      --border: #000080;
      --mdLink: #000080;
      --syntaxKeyword: #000080;
      --syntaxVariable: #008080;
      --success: #008000;
      --mdCodeBlock: #008000;
      --toolDiffAdded: #008000;
      --bashMode: #008000;
      --syntaxNumber: #800080;
      --error: #800000;
      --toolDiffRemoved: #800000;
      --warning: #808000;
      --mdHeading: #808000;
      --syntaxFunction: #808000;
      --syntaxString: #008000;
      --thinkingMinimal: #000080;
      --thinkingLow: #000080;
      --thinkingMedium: #008080;
      --thinkingHigh: #800080;
      --thinkingXhigh: #ff00ff;
      --thinkingMax: #800000;
      --text: #e5e5e7;
      --userMessageText: #e5e5e7;
      --customMessageText: #727273;
      --toolTitle: #e5e5e7;
      --syntaxOperator: #727273;
      --syntaxPunctuation: #727273;
      --muted: #727273;
      --dim: #727273;
      --thinkingText: #727273;
      --toolOutput: #727273;
      --mdLinkUrl: #727273;
      --mdQuote: #727273;
      --mdQuoteBorder: #727273;
      --mdHr: #727273;
      --mdCodeBlockBorder: #727273;
      --toolDiffContext: #727273;
      --syntaxComment: #727273;
      --scrollbarTrack: #727273;
      --scrollbarThumb: #727273;
      --searchMatchText: #727273;
      --borderMuted: #727273;
      --thinkingOff: #727273;
      --selectedBg: #000000;
      --searchMatchBg: #000000;
      --userMessageBg: #000000;
      --customMessageBg: #000000;
      --toolPendingBg: #000000;
      --toolSuccessBg: #000000;
      --toolErrorBg: #000000;
      --exportPageBg: rgb(0, 0, 0);
      --exportCardBg: rgb(0, 0, 0);
      --exportInfoBg: rgb(20, 15, 0);
      --body-bg: rgb(0, 0, 0);
      --container-bg: rgb(0, 0, 0);
      --info-bg: rgb(20, 15, 0);
    }

    * { margin: 0; padding: 0; box-sizing: border-box; }

    :root {
      --line-height: 18px; /* 12px font * 1.5 */
      --sidebar-width: 400px;
      --sidebar-min-width: 240px;
      --sidebar-max-width: 840px;
      --sidebar-resizer-width: 6px;
    }

    body {
      font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
      font-size: 12px;
      line-height: var(--line-height);
      color: var(--text);
      background: var(--body-bg);
    }

    body.sidebar-resizing {
      cursor: col-resize;
      user-select: none;
    }

    #app {
      display: flex;
      min-height: 100vh;
    }

    /* Sidebar */
    #sidebar {
      width: var(--sidebar-width);
      min-width: var(--sidebar-width);
      max-width: var(--sidebar-width);
      background: var(--container-bg);
      flex-shrink: 0;
      display: flex;
      flex-direction: column;
      position: sticky;
      top: 0;
      height: 100vh;
      border-right: 1px solid var(--dim);
    }

    #sidebar-resizer {
      width: var(--sidebar-resizer-width);
      flex-shrink: 0;
      position: sticky;
      top: 0;
      height: 100vh;
      cursor: col-resize;
      touch-action: none;
      background: transparent;
      border-right: 1px solid transparent;
    }

    #sidebar-resizer:hover,
    body.sidebar-resizing #sidebar-resizer {
      background: var(--selectedBg);
      border-right-color: var(--dim);
    }

    .sidebar-header {
      padding: 8px 12px;
      flex-shrink: 0;
    }

    .sidebar-controls {
      padding: 8px 8px 4px 8px;
    }

    .sidebar-search {
      width: 100%;
      box-sizing: border-box;
      padding: 4px 8px;
      font-size: 11px;
      font-family: inherit;
      background: var(--body-bg);
      color: var(--text);
      border: 1px solid var(--dim);
      border-radius: 3px;
    }

    .sidebar-filters {
      display: flex;
      padding: 4px 8px 8px 8px;
      gap: 4px;
      align-items: center;
      flex-wrap: wrap;
    }

    .sidebar-search:focus {
      outline: none;
      border-color: var(--accent);
    }

    .sidebar-search::placeholder {
      color: var(--muted);
    }

    .filter-btn {
      padding: 3px 8px;
      font-size: 10px;
      font-family: inherit;
      background: transparent;
      color: var(--muted);
      border: 1px solid var(--dim);
      border-radius: 3px;
      cursor: pointer;
    }

    .filter-btn:hover {
      color: var(--text);
      border-color: var(--text);
    }

    .filter-btn.active {
      background: var(--accent);
      color: var(--body-bg);
      border-color: var(--accent);
    }

    .sidebar-close {
      display: none;
      padding: 3px 8px;
      font-size: 12px;
      font-family: inherit;
      background: transparent;
      color: var(--muted);
      border: 1px solid var(--dim);
      border-radius: 3px;
      cursor: pointer;
      margin-left: auto;
    }

    .sidebar-close:hover {
      color: var(--text);
      border-color: var(--text);
    }

    .tree-container {
      flex: 1;
      overflow: auto;
      padding: 4px 0;
    }

    .tree-node {
      padding: 0 8px;
      cursor: pointer;
      display: flex;
      align-items: baseline;
      font-size: 11px;
      line-height: 13px;
      white-space: nowrap;
    }

    .tree-node:hover {
      background: var(--selectedBg);
    }

    .tree-node.active {
      background: var(--selectedBg);
    }

    .tree-node.active .tree-content {
      font-weight: bold;
    }

    .tree-node.in-path {
      background: color-mix(in srgb, var(--accent) 10%, transparent);
    }

    .tree-node:not(.in-path) {
      opacity: 0.5;
    }

    .tree-node:not(.in-path):hover {
      opacity: 1;
    }

    .tree-prefix {
      color: var(--muted);
      flex-shrink: 0;
      font-family: monospace;
      white-space: pre;
    }

    .tree-marker {
      color: var(--accent);
      flex-shrink: 0;
    }

    .tree-content {
      color: var(--text);
    }

    .tree-role-user {
      color: var(--accent);
    }

    .tree-role-skill {
      color: var(--customMessageLabel);
    }

    .tree-role-assistant {
      color: var(--success);
    }

    .tree-role-tool {
      color: var(--muted);
    }

    .tree-muted {
      color: var(--muted);
    }

    .tree-error {
      color: var(--error);
    }

    .tree-compaction {
      color: var(--borderAccent);
    }

    .tree-branch-summary {
      color: var(--warning);
    }

    .tree-custom-message {
      color: var(--customMessageLabel);
    }

    .tree-status {
      padding: 4px 12px;
      font-size: 10px;
      color: var(--muted);
      flex-shrink: 0;
    }

    /* Main content */
    #content {
      flex: 1;
      min-width: 0;
      overflow-y: auto;
      padding: var(--line-height) calc(var(--line-height) * 2);
      display: flex;
      flex-direction: column;
      align-items: center;
    }

    #content > * {
      width: 100%;
      max-width: 800px;
    }

    /* Help bar */
    .help-bar {
      font-size: 11px;
      color: var(--warning);
      margin-bottom: var(--line-height);
      display: flex;
      align-items: center;
      justify-content: space-between;
      flex-wrap: wrap;
      gap: 12px;
    }

    .help-hint {
      flex: 1 1 240px;
    }

    .help-actions {
      display: flex;
      align-items: center;
      flex-wrap: wrap;
      gap: 8px;
    }

    .header-toggle-btn,
    .download-json-btn {
      font-size: 10px;
      padding: 2px 8px;
      background: var(--container-bg);
      border: 1px solid var(--border);
      border-radius: 3px;
      color: var(--text);
      cursor: pointer;
      font-family: inherit;
    }

    .header-toggle-btn:hover,
    .download-json-btn:hover {
      background: var(--hover);
      border-color: var(--borderAccent);
    }

    .header-toggle-btn[aria-pressed="true"] {
      color: var(--accent);
      border-color: var(--accent);
      font-weight: bold;
    }

    /* Header */
    .header {
      background: var(--container-bg);
      border-radius: 4px;
      paddin

... [284230 bytes truncated] ...

hare:v1:sidebar-width';
      const MIN_CONTENT_WIDTH = 320;

      function isMobileLayout() {
        return window.matchMedia('(max-width: 900px)').matches;
      }

      function getSidebarBounds() {
        const rootStyles = getComputedStyle(document.documentElement);
        const minWidth = parseFloat(rootStyles.getPropertyValue('--sidebar-min-width')) || 240;
        const maxWidth = parseFloat(rootStyles.getPropertyValue('--sidebar-max-width')) || 720;
        const viewportMaxWidth = window.innerWidth - MIN_CONTENT_WIDTH;
        return {
          minWidth,
          maxWidth: Math.max(minWidth, Math.min(maxWidth, viewportMaxWidth))
        };
      }

      function clampSidebarWidth(width) {
        const { minWidth, maxWidth } = getSidebarBounds();
        return Math.max(minWidth, Math.min(maxWidth, width));
      }

      function applySidebarWidth(width) {
        document.documentElement.style.setProperty('--sidebar-width', `${Math.round(clampSidebarWidth(width))}px`);
      }

      function loadSidebarWidth() {
        try {
          const raw = localStorage.getItem(SIDEBAR_WIDTH_STORAGE_KEY);
          if (raw === null) return null;
          const width = Number(raw);
          return Number.isFinite(width) ? width : null;
        } catch {
          return null;
        }
      }

      function saveSidebarWidth(width) {
        try {
          localStorage.setItem(SIDEBAR_WIDTH_STORAGE_KEY, String(Math.round(clampSidebarWidth(width))));
        } catch {
          // Ignore storage failures (e.g. private browsing restrictions)
        }
      }

      function setupSidebarResize() {
        const savedWidth = loadSidebarWidth();
        if (savedWidth !== null) {
          applySidebarWidth(savedWidth);
        }

        if (!sidebarResizer) return;

        let cleanupDrag = null;

        const stopDrag = (pointerId) => {
          if (cleanupDrag) {
            cleanupDrag(pointerId);
            cleanupDrag = null;
          }
        };

        sidebarResizer.addEventListener('pointerdown', (e) => {
          if (isMobileLayout()) return;

          e.preventDefault();
          const startX = e.clientX;
          const startWidth = sidebar.getBoundingClientRect().width;
          document.body.classList.add('sidebar-resizing');
          sidebarResizer.setPointerCapture?.(e.pointerId);

          const onPointerMove = (event) => {
            applySidebarWidth(startWidth + (event.clientX - startX));
          };

          cleanupDrag = (pointerIdToRelease) => {
            document.body.classList.remove('sidebar-resizing');
            sidebarResizer.releasePointerCapture?.(pointerIdToRelease);
            window.removeEventListener('pointermove', onPointerMove);
            window.removeEventListener('pointerup', onPointerUp);
            window.removeEventListener('pointercancel', onPointerCancel);
            saveSidebarWidth(sidebar.getBoundingClientRect().width);
          };

          const onPointerUp = (event) => stopDrag(event.pointerId);
          const onPointerCancel = (event) => stopDrag(event.pointerId);

          window.addEventListener('pointermove', onPointerMove);
          window.addEventListener('pointerup', onPointerUp);
          window.addEventListener('pointercancel', onPointerCancel);
        });

        sidebarResizer.addEventListener('dblclick', () => {
          if (isMobileLayout()) return;
          applySidebarWidth(400);
          saveSidebarWidth(400);
        });

        window.addEventListener('resize', () => {
          if (isMobileLayout()) return;
          applySidebarWidth(sidebar.getBoundingClientRect().width);
        });
      }

      setupSidebarResize();

      hamburger.addEventListener('click', () => {
        sidebar.classList.add('open');
        overlay.classList.add('open');
        hamburger.style.display = 'none';
      });

      const closeSidebar = () => {
        sidebar.classList.remove('open');
        overlay.classList.remove('open');
        hamburger.style.display = '';
      };

      overlay.addEventListener('click', closeSidebar);
      document.getElementById('sidebar-close').addEventListener('click', closeSidebar);

      // Toggle states
      let thinkingExpanded = true;
      let toolOutputsExpanded = false;
      let showHiddenMessages = false;

      function setHiddenMessagesVisible(visible) {
        showHiddenMessages = visible;
        document.body.classList.toggle('show-hidden-messages', visible);
        const button = document.querySelector('[data-action="toggle-hidden-messages"]');
        if (button) {
          button.setAttribute('aria-pressed', String(visible));
          button.textContent = visible ? 'Hide hidden messages' : 'Show hidden messages';
        }
      }

      function setThinkingExpanded(expanded) {
        thinkingExpanded = expanded;
        document.querySelector('[data-action="toggle-thinking"]')?.setAttribute('aria-pressed', String(expanded));
        document.querySelectorAll('.thinking-text').forEach(el => {
          el.style.display = thinkingExpanded ? '' : 'none';
        });
        document.querySelectorAll('.thinking-collapsed').forEach(el => {
          el.style.display = thinkingExpanded ? 'none' : 'block';
        });
      }

      function setToolOutputsExpanded(expanded) {
        toolOutputsExpanded = expanded;
        document.querySelector('[data-action="toggle-tools"]')?.setAttribute('aria-pressed', String(expanded));
        document.querySelectorAll('.tool-output.expandable').forEach(el => {
          el.classList.toggle('expanded', toolOutputsExpanded);
        });
        document.querySelectorAll('.compaction').forEach(el => {
          el.classList.toggle('expanded', toolOutputsExpanded);
        });
        document.querySelectorAll('.skill-invocation').forEach(el => {
          el.classList.toggle('expanded', toolOutputsExpanded);
        });
      }

      const attachHeaderHandlers = () => {
        document.querySelector('[data-action="toggle-thinking"]')?.addEventListener('click', () => {
          setThinkingExpanded(!thinkingExpanded);
        });
        document.querySelector('[data-action="toggle-tools"]')?.addEventListener('click', () => {
          setToolOutputsExpanded(!toolOutputsExpanded);
        });
        document.querySelector('[data-action="toggle-hidden-messages"]')?.addEventListener('click', () => {
          setHiddenMessagesVisible(!showHiddenMessages);
        });
      };

      const isEditableTarget = (element) => {
        if (!element) return false;
        const tagName = element.tagName;
        if (tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT' || tagName === 'BUTTON') {
          return true;
        }
        return element.isContentEditable || Boolean(element.closest?.('[contenteditable="true"]'));
      };

      // Keyboard shortcuts
      document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape') {
          searchInput.value = '';
          searchQuery = '';
          navigateTo(leafId, 'bottom');
        }

        if (e.ctrlKey || e.metaKey || e.altKey || isEditableTarget(document.activeElement)) {
          return;
        }

        const key = e.key.toLowerCase();
        if (key === 't') {
          e.preventDefault();
          setThinkingExpanded(!thinkingExpanded);
        } else if (key === 'o') {
          e.preventDefault();
          setToolOutputsExpanded(!toolOutputsExpanded);
        } else if (key === 'h') {
          e.preventDefault();
          setHiddenMessagesVisible(!showHiddenMessages);
        }
      });

      // Initial render
      // If URL has targetId, scroll to that specific message; otherwise stay at top
      if (leafId) {
        if (urlTargetId && byId.has(urlTargetId)) {
          // Deep link: navigate to leaf and scroll to target message
          navigateTo(leafId, 'target', urlTargetId);
        } else {
          navigateTo(leafId, 'none');
        }
      } else if (entries.length > 0) {
        // Fallback: use last entry if no leafId
        navigateTo(entries[entries.length - 1].id, 'none');
      }
    })();

  </script>
</body>
</html>
Evidence: Real remote-home provisioning completed during source repack

Source: Real remote-home provisioning completed during source repack

provisioned: ~/.no-mistakes/worktrees/32d18ed9638d/01M44P33S4FCMC3A82HAN56PSW/.gate-test-lab/tmp/fm-remote-secondmate-e2e.cF3CSz/repacked-home projects=0
Evidence: Provisioning refuses a competing foreign home

Source: Provisioning refuses a competing foreign home

error: remote home appeared while it was being provisioned

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • ⚠️ tests/fm-calm-pi-extension.test.sh:1653 - The HTML fixture now supports only Pi 1.0.2's lookup interface, regressing verification on documented older versions. Pi 0.99.0's createToolHtmlRenderer invokes getToolDefinition; supplying only getToolRenderers causes a caught lookup error and returns undefined. Consequently, assertStockHtmlRendering('/export calm.html', '\r') fails despite correct Calm behavior. The same invariant must hold at tests/fm-calm-pi-extension.test.sh:1684 (the non-submit assertion instead passes on lookup failure) and tests/fm-pi-branch-extension.test.sh:5112 and :5113 (both fallback assertions can pass without invoking either renderer). Preserve both vendor lookup interfaces in these fixtures rather than implicitly raising their supported version. Vendor evidence: https://unpkg.com/@earendil-works/pi-coding-agent@0.99.0/dist/core/export-html/tool-renderer.js

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 8 of 8 scenarios driven live against the product
Scenario Result Live Evidence
Read supervision outcomes with stock argument previews and expand the full result ✅ pass live branch-live/pi102-stock-collapsed.txt and pi099-stock-collapsed.txt; corresponding stock-expanded captures.
Submit invalid and unowned acknowledgements without losing stock error presentation ✅ pass live branch-live/pi102-browser-errors.png, pi099-browser-errors.png, and native exported toolResult data.
Toggle Calm around supervision tools and export without leaving hidden rows visible ✅ pass live branch-live/pi102- and pi099-calm-hidden.txt, calm-after-export.txt, calm-restored.txt, and actual HTML exports.
Export a Calm conversation while retaining genuine turns and stock operational history ✅ pass live Pi 1.0.2 and 0.99.0 exported conversation screenshots, generated HTML, and browser-export-observations.json.
Explicitly reveal hidden export history, then restore the conversation boundary ✅ pass live Both versions' export-hidden-revealed.png screenshots and browser-export-observations.json.
Reload and resume Calm without changing regular replay or hidden-block geometry ✅ pass live Original live Calm acceptance on both versions, including native /reload, expansion and restart; preserved restarted.txt and restored.txt captures.
Provision a remote home while the source repository repacks ✅ pass live Provision-only executable scenario; remote-repack-provision.out, remote-provisioned-home.txt, and destination fsck before and after source-object removal.
Race provisioning with another attempt, cleanup and a foreign destination ✅ pass live Provision-only executable scenarios and remote-appeared-provision.out.
  • pi --version and npm root -g identified the installed runtime; workspace-local npm install --prefix .gate-test-lab/vendor099 --no-audit --no-fund --ignore-scripts @earendil-works/pi-coding-agent@0.99.0 supplied the older vendor.
  • Ran all original Calm acceptance cases through bash tests/.gate-calm-validation.sh on Pi 1.0.2 and bash tests/.gate-calm099-validation.sh on Pi 0.99.0. Disposable drivers changed only teardown to preserve generated evidence. An initial overlong tmux socket path was corrected before successful runs.
  • Ran bash tests/fm-pi-branch-extension.test.sh with FM_PI_PACKAGE_DIR selecting Pi 1.0.2 and 0.99.0, preserving the full original 64-case combined Calm/branch acceptance.
  • Ran FM_TEST_PROVISION_ONLY=1 bash tests/.gate-remote-validation.sh. The disposable driver excluded the workspace-local lab from fixture copying and preserved evidence; provisioning assertions were unchanged.
  • Launched real Pi CLIs with isolated home/config/session directories and production Calm/branch extensions. A deterministic local provider caused actual fm_branch_outcomes(recent=14) and fm_branch_processed(through=0/999) execution. Exact launch commands are preserved in branch-live/launched-command.txt and launched-command099.txt.
  • Drove native Ctrl+O, /calm, /export, and /calm restoration on both Pi versions; captured terminal panes and native exported session data.
  • Loaded actual generated exports in isolated Chromium, clicked Show hidden messages twice and Toggle tools, checked visible conversation boundaries and stock expansion, and captured screenshots.
  • Stopped isolated Pi/tmux and HTTP server processes, closed the browser tab, removed disposable drivers/dependencies/fixtures, and verified their removal.
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@MrGTV-love
MrGTV-love force-pushed the fm/fm-pi-render-drift branch from 7801c01 to a0b9cc2 Compare October 4, 2026 20:05
@MrGTV-love MrGTV-love changed the title fix(pi): delegate supervision tool rendering to stock Pi and fix export DOM check for Pi 0.99 fix: preserve stock Pi rendering and prevent remote provisioning races Oct 4, 2026
…igrated all four HTML-renderer fixture callers across the Calm and branch tests from obsolete getToolDefinition to Pi 1.0.2's getToolRenderers. Replaced the non-triggering Linux libc interposer with Git's real pack-creation hook, configured through a private fixture config; the portable regression verifies successful provisioning and object independence after removing source objects. Updated matching documentation and removed temporary verification artifacts. Verification passed: focused Calm renderer/lifecycle and branch rendering/export cases against Pi 1.0.2, provision-only lifecycle including the source-repack regression, and shell syntax checks. Full lifecycle verification reached a later unrelated restart-checkpoint assertion but failed because worktree-contained temporary fixtures discovered the enclosing checkout; a Git ceiling override did not resolve that local limitation. No pipeline, push, or other gate phase was invoked
…e in tests/fm-calm-pi-extension.test.sh. The reload geometry check incorrectly required sampling a transient progress banner, so it could fail after a successful reload. Removed the single-use transient helper and now wait for Pi’s persistent reload-completion status before asserting transcript geometry. Checked sibling transitions; none require transient-first sampling. Updated the existing verification documentation. Against worktree-local Pi 1.0.2, delaying the first post-command viewport sample reproduced the failure before the fix and passed afterward, including thinking expansion/collapse, Calm off/on, persisted history, and restart. Shell syntax passed. The affected-suite run passed the repaired geometry check and all preceding checks, but failed later in the separate interactive fixture because its initial capture lacked CALM_E2E_OUTPUT; a full-suite pass is not claimed. Removed all temporary verification scaffolding. No pipeline-control, push, or other gate phase was invoked
…s/fm-calm-pi-extension.test.sh. Pi 1.0.2 draws only the visible transcript tail on restore; the 44-row fixture clipped CALM_E2E_OUTPUT before it was ever drawn, so tmux scrollback could not recover it and the Calm-off assertion failed. Increased terminal height to 200 rows for initial restore, transcript visibility checks, and restart, while preserving the short and narrow working-ship resize probes. Updated the existing verification documentation. Reproduced the exact failure locally before the fix; afterward, the complete interactive scenario and all 15 cases in the affected Calm suite passed against Pi 1.0.2, including real Chrome export-DOM assertions, Ctrl+O, Calm toggles, restart, and resize behavior. Shell syntax passed. Removed temporary verification artifacts. The full serial shard was not rerun; no pipeline-control, push, or other gate phase was invoked
@MrGTV-love MrGTV-love changed the title fix: preserve stock Pi rendering and prevent remote provisioning races fix: preserve Pi stock rendering and stabilize remote provisioning Oct 5, 2026
@MrGTV-love
MrGTV-love merged commit 6bec7da into main Oct 5, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant