Spec 146 phase 11: codev-client tree and live status #220

Description

@pseudoseed

Spec 146 phase 11. This is the first phase of the initiative that produces something a human can
look at.
Phases 1-9 are plumbing: the contract, the transport, the driver, delivery semantics,
the state service, approvals, security, thread identity, and afx parity. All of that is on main
and none of it is visible. This phase is the payoff, and it should be treated as the priority it
is.

The plan section is reproduced below verbatim so it is not fetched by path.


Phase 11: codev-client tree and live status

Dependencies: Phase 6, Phase 7, Phase 9

Objective

The left sidebar tree: machine, workspace, architects, that architect's builders, with correct live
status on every row — including a builder blocked on a gate showing #128's structured question, not
only a gate name. Multi-machine and honest degradation land here too, because a tree that cannot
say "disconnected" is worse than no tree.

The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright.

Files to Create / Modify

  • apps/client/package.json, vite.config.ts, tsconfig.json
  • apps/client/src/tree/ — the workspace tree.
  • apps/client/src/connection/ — per-machine connection, one per server.
  • apps/client/src/status/ — row status derivation.
  • apps/client/src/gate/ — structured gate rendering and approval.
  • apps/client/e2e/

Deliverables

  • The tree renders machine, workspace, architects, and each architect's builders.
  • Every row carries live status: working, turning, blocked on a named gate, or settled.
  • A blocked builder shows its structured question and choices without navigation, and is
    visually distinct from a settled one. A gate name alone does not satisfy this.
  • Where porch and t3code disagree, porch wins and the client shows porch's value. Titles,
    pins and activity entries are display projections, never a source of truth.
  • A thread with no porch record renders as unmanaged, not hidden.
  • One client connects to more than one machine's server at once, each independently live.
  • With one server stopped, its subtree is marked disconnected with a last-updated
    timestamp
    , other machines stay live, and nothing renders blank or silently stale.
  • A human approves a real gate from the client through Phase 6's capability path.
  • No dangerouslySetInnerHTML on agent output; a restrictive CSP; explicit origin rules. The
    client holds credentials for N servers, which makes XSS a credential-theft path rather than a
    defacement one.
  • Tests for this phase.

Acceptance Criteria

  • Criterion 3: correct live status on every row including the structured gate content.
  • Criterion 7: two machines in one tree, independently live.
  • Criterion 8: one server stopped, subtree disconnected with a timestamp, others unaffected.
  • Criterion 9b: a real gate approved from the client, with session id, machine and timestamp in
    status.yaml.
  • Criterion 15's scenario: revoking one machine's token fails that subtree closed and leaves
    others unaffected.
  • A grep asserts no dangerouslySetInnerHTML in the app.
  • Build and tests pass.

Test Plan

Unit and component: status derivation for every state; the porch-wins reconciliation; disconnected
rendering.

E2E under Playwright against two live servers: both trees correct, one stopped, the subtree marked,
a gate approved.



Architect notes

Dependencies are satisfied. Phase 6 (agent-farm/lib/approval-capability.ts) and phase 7
(agent-farm/lib/machine-credentials.ts) are on main. Phase 9 is on mainpartial — items
3 and 4 of #179 (an architect thread in production; a thread surviving a server restart with
context) are being run under #219 in parallel with this work. Nothing in phase 11 blocks on them.

The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright. Follow that app's
conventions rather than inventing new ones.

A green test suite cannot detect design infidelity. This repo has shipped a client that passed
127 client tests, 3,394 server tests and 15/15 Playwright with correct tokens and correct colour
discipline, and was unusable — it had dropped every label prefix, the header bar, and rendered
idle sparklines as invisible dots (#112). Component tests that assert "the name renders" pass
happily while the thing that made the name legible is gone. Open the running client and look at
it before you call any of this done.

A pinned t3 server is already running on 127.0.0.1:3799 at commit 082e6ea52186, started
with T3_NODE=/opt/homebrew/bin/node node tools/t3-server/t3-server.mjs start. T3_NODE must be
an absolute interpreter path; the harness refuses to inherit its Node from PATH and reports
NO_INTERPRETER: could not check rather than guessing. Re-verify the pin yourself with status.

The two-server criteria need a second server. Criterion 7 (two machines in one tree) and
criterion 8 (one stopped, its subtree disconnected with a timestamp) cannot be satisfied against a
single server, and a single-server approximation of them is not evidence. Work out how to stand up
the second instance early rather than at the end.

On honest degradation, which is the deliverable most easily faked. "Disconnected" must be
distinguishable from "connected and idle" and from "connected and empty". A subtree that renders
blank, or renders its last known state without saying when that state is from, has failed
criterion 8 regardless of what the test asserts. This repo's standing rule is that "I could not
tell" must never be spelled the same way as "no" — three separate defects of exactly that shape
landed in one day (#214, #216, #217). The last-updated timestamp is what makes the difference
observable, so it is not decoration.

Where porch and t3code disagree, porch wins. Titles, pins and activity entries from t3code are
display projections, never a source of truth.

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

    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 \u003cpre\u003e\u003ccode\u003e 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

      Spec 146 phase 11: codev-client tree and live status #220

      Description

      @pseudoseed

      Spec 146 phase 11. This is the first phase of the initiative that produces something a human can
      look at.
      Phases 1-9 are plumbing: the contract, the transport, the driver, delivery semantics,
      the state service, approvals, security, thread identity, and afx parity. All of that is on main
      and none of it is visible. This phase is the payoff, and it should be treated as the priority it
      is.

      The plan section is reproduced below verbatim so it is not fetched by path.


      Phase 11: codev-client tree and live status

      Dependencies: Phase 6, Phase 7, Phase 9

      Objective

      The left sidebar tree: machine, workspace, architects, that architect's builders, with correct live
      status on every row — including a builder blocked on a gate showing #128's structured question, not
      only a gate name. Multi-machine and honest degradation land here too, because a tree that cannot
      say "disconnected" is worse than no tree.

      The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright.

      Files to Create / Modify

      • apps/client/package.json, vite.config.ts, tsconfig.json
      • apps/client/src/tree/ — the workspace tree.
      • apps/client/src/connection/ — per-machine connection, one per server.
      • apps/client/src/status/ — row status derivation.
      • apps/client/src/gate/ — structured gate rendering and approval.
      • apps/client/e2e/

      Deliverables

      • The tree renders machine, workspace, architects, and each architect's builders.
      • Every row carries live status: working, turning, blocked on a named gate, or settled.
      • A blocked builder shows its structured question and choices without navigation, and is
        visually distinct from a settled one. A gate name alone does not satisfy this.
      • Where porch and t3code disagree, porch wins and the client shows porch's value. Titles,
        pins and activity entries are display projections, never a source of truth.
      • A thread with no porch record renders as unmanaged, not hidden.
      • One client connects to more than one machine's server at once, each independently live.
      • With one server stopped, its subtree is marked disconnected with a last-updated
        timestamp
        , other machines stay live, and nothing renders blank or silently stale.
      • A human approves a real gate from the client through Phase 6's capability path.
      • No dangerouslySetInnerHTML on agent output; a restrictive CSP; explicit origin rules. The
        client holds credentials for N servers, which makes XSS a credential-theft path rather than a
        defacement one.
      • Tests for this phase.

      Acceptance Criteria

      • Criterion 3: correct live status on every row including the structured gate content.
      • Criterion 7: two machines in one tree, independently live.
      • Criterion 8: one server stopped, subtree disconnected with a timestamp, others unaffected.
      • Criterion 9b: a real gate approved from the client, with session id, machine and timestamp in
        status.yaml.
      • Criterion 15's scenario: revoking one machine's token fails that subtree closed and leaves
        others unaffected.
      • A grep asserts no dangerouslySetInnerHTML in the app.
      • Build and tests pass.

      Test Plan

      Unit and component: status derivation for every state; the porch-wins reconciliation; disconnected
      rendering.

      E2E under Playwright against two live servers: both trees correct, one stopped, the subtree marked,
      a gate approved.



      Architect notes

      Dependencies are satisfied. Phase 6 (agent-farm/lib/approval-capability.ts) and phase 7
      (agent-farm/lib/machine-credentials.ts) are on main. Phase 9 is on mainpartial — items
      3 and 4 of #179 (an architect thread in production; a thread surviving a server restart with
      context) are being run under #219 in parallel with this work. Nothing in phase 11 blocks on them.

      The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright. Follow that app's
      conventions rather than inventing new ones.

      A green test suite cannot detect design infidelity. This repo has shipped a client that passed
      127 client tests, 3,394 server tests and 15/15 Playwright with correct tokens and correct colour
      discipline, and was unusable — it had dropped every label prefix, the header bar, and rendered
      idle sparklines as invisible dots (#112). Component tests that assert "the name renders" pass
      happily while the thing that made the name legible is gone. Open the running client and look at
      it before you call any of this done.

      A pinned t3 server is already running on 127.0.0.1:3799 at commit 082e6ea52186, started
      with T3_NODE=/opt/homebrew/bin/node node tools/t3-server/t3-server.mjs start. T3_NODE must be
      an absolute interpreter path; the harness refuses to inherit its Node from PATH and reports
      NO_INTERPRETER: could not check rather than guessing. Re-verify the pin yourself with status.

      The two-server criteria need a second server. Criterion 7 (two machines in one tree) and
      criterion 8 (one stopped, its subtree disconnected with a timestamp) cannot be satisfied against a
      single server, and a single-server approximation of them is not evidence. Work out how to stand up
      the second instance early rather than at the end.

      On honest degradation, which is the deliverable most easily faked. "Disconnected" must be
      distinguishable from "connected and idle" and from "connected and empty". A subtree that renders
      blank, or renders its last known state without saying when that state is from, has failed
      criterion 8 regardless of what the test asserts. This repo's standing rule is that "I could not
      tell" must never be spelled the same way as "no" — three separate defects of exactly that shape
      landed in one day (#214, #216, #217). The last-updated timestamp is what makes the difference
      observable, so it is not decoration.

      Where porch and t3code disagree, porch wins. Titles, pins and activity entries from t3code are
      display projections, never a source of truth.

      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

        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

          Spec 146 phase 11: codev-client tree and live status #220

          Description

          @pseudoseed

          Spec 146 phase 11. This is the first phase of the initiative that produces something a human can
          look at.
          Phases 1-9 are plumbing: the contract, the transport, the driver, delivery semantics,
          the state service, approvals, security, thread identity, and afx parity. All of that is on main
          and none of it is visible. This phase is the payoff, and it should be treated as the priority it
          is.

          The plan section is reproduced below verbatim so it is not fetched by path.


          Phase 11: codev-client tree and live status

          Dependencies: Phase 6, Phase 7, Phase 9

          Objective

          The left sidebar tree: machine, workspace, architects, that architect's builders, with correct live
          status on every row — including a builder blocked on a gate showing #128's structured question, not
          only a gate name. Multi-machine and honest degradation land here too, because a tree that cannot
          say "disconnected" is worse than no tree.

          The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright.

          Files to Create / Modify

          • apps/client/package.json, vite.config.ts, tsconfig.json
          • apps/client/src/tree/ — the workspace tree.
          • apps/client/src/connection/ — per-machine connection, one per server.
          • apps/client/src/status/ — row status derivation.
          • apps/client/src/gate/ — structured gate rendering and approval.
          • apps/client/e2e/

          Deliverables

          • The tree renders machine, workspace, architects, and each architect's builders.
          • Every row carries live status: working, turning, blocked on a named gate, or settled.
          • A blocked builder shows its structured question and choices without navigation, and is
            visually distinct from a settled one. A gate name alone does not satisfy this.
          • Where porch and t3code disagree, porch wins and the client shows porch's value. Titles,
            pins and activity entries are display projections, never a source of truth.
          • A thread with no porch record renders as unmanaged, not hidden.
          • One client connects to more than one machine's server at once, each independently live.
          • With one server stopped, its subtree is marked disconnected with a last-updated
            timestamp
            , other machines stay live, and nothing renders blank or silently stale.
          • A human approves a real gate from the client through Phase 6's capability path.
          • No dangerouslySetInnerHTML on agent output; a restrictive CSP; explicit origin rules. The
            client holds credentials for N servers, which makes XSS a credential-theft path rather than a
            defacement one.
          • Tests for this phase.

          Acceptance Criteria

          • Criterion 3: correct live status on every row including the structured gate content.
          • Criterion 7: two machines in one tree, independently live.
          • Criterion 8: one server stopped, subtree disconnected with a timestamp, others unaffected.
          • Criterion 9b: a real gate approved from the client, with session id, machine and timestamp in
            status.yaml.
          • Criterion 15's scenario: revoking one machine's token fails that subtree closed and leaves
            others unaffected.
          • A grep asserts no dangerouslySetInnerHTML in the app.
          • Build and tests pass.

          Test Plan

          Unit and component: status derivation for every state; the porch-wins reconciliation; disconnected
          rendering.

          E2E under Playwright against two live servers: both trees correct, one stopped, the subtree marked,
          a gate approved.



          Architect notes

          Dependencies are satisfied. Phase 6 (agent-farm/lib/approval-capability.ts) and phase 7
          (agent-farm/lib/machine-credentials.ts) are on main. Phase 9 is on mainpartial — items
          3 and 4 of #179 (an architect thread in production; a thread surviving a server restart with
          context) are being run under #219 in parallel with this work. Nothing in phase 11 blocks on them.

          The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright. Follow that app's
          conventions rather than inventing new ones.

          A green test suite cannot detect design infidelity. This repo has shipped a client that passed
          127 client tests, 3,394 server tests and 15/15 Playwright with correct tokens and correct colour
          discipline, and was unusable — it had dropped every label prefix, the header bar, and rendered
          idle sparklines as invisible dots (#112). Component tests that assert "the name renders" pass
          happily while the thing that made the name legible is gone. Open the running client and look at
          it before you call any of this done.

          A pinned t3 server is already running on 127.0.0.1:3799 at commit 082e6ea52186, started
          with T3_NODE=/opt/homebrew/bin/node node tools/t3-server/t3-server.mjs start. T3_NODE must be
          an absolute interpreter path; the harness refuses to inherit its Node from PATH and reports
          NO_INTERPRETER: could not check rather than guessing. Re-verify the pin yourself with status.

          The two-server criteria need a second server. Criterion 7 (two machines in one tree) and
          criterion 8 (one stopped, its subtree disconnected with a timestamp) cannot be satisfied against a
          single server, and a single-server approximation of them is not evidence. Work out how to stand up
          the second instance early rather than at the end.

          On honest degradation, which is the deliverable most easily faked. "Disconnected" must be
          distinguishable from "connected and idle" and from "connected and empty". A subtree that renders
          blank, or renders its last known state without saying when that state is from, has failed
          criterion 8 regardless of what the test asserts. This repo's standing rule is that "I could not
          tell" must never be spelled the same way as "no" — three separate defects of exactly that shape
          landed in one day (#214, #216, #217). The last-updated timestamp is what makes the difference
          observable, so it is not decoration.

          Where porch and t3code disagree, porch wins. Titles, pins and activity entries from t3code are
          display projections, never a source of truth.

          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

            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 \u003e 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

              Spec 146 phase 11: codev-client tree and live status #220

              Description

              @pseudoseed

              Spec 146 phase 11. This is the first phase of the initiative that produces something a human can
              look at.
              Phases 1-9 are plumbing: the contract, the transport, the driver, delivery semantics,
              the state service, approvals, security, thread identity, and afx parity. All of that is on main
              and none of it is visible. This phase is the payoff, and it should be treated as the priority it
              is.

              The plan section is reproduced below verbatim so it is not fetched by path.


              Phase 11: codev-client tree and live status

              Dependencies: Phase 6, Phase 7, Phase 9

              Objective

              The left sidebar tree: machine, workspace, architects, that architect's builders, with correct live
              status on every row — including a builder blocked on a gate showing #128's structured question, not
              only a gate name. Multi-machine and honest degradation land here too, because a tree that cannot
              say "disconnected" is worse than no tree.

              The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright.

              Files to Create / Modify

              • apps/client/package.json, vite.config.ts, tsconfig.json
              • apps/client/src/tree/ — the workspace tree.
              • apps/client/src/connection/ — per-machine connection, one per server.
              • apps/client/src/status/ — row status derivation.
              • apps/client/src/gate/ — structured gate rendering and approval.
              • apps/client/e2e/

              Deliverables

              • The tree renders machine, workspace, architects, and each architect's builders.
              • Every row carries live status: working, turning, blocked on a named gate, or settled.
              • A blocked builder shows its structured question and choices without navigation, and is
                visually distinct from a settled one. A gate name alone does not satisfy this.
              • Where porch and t3code disagree, porch wins and the client shows porch's value. Titles,
                pins and activity entries are display projections, never a source of truth.
              • A thread with no porch record renders as unmanaged, not hidden.
              • One client connects to more than one machine's server at once, each independently live.
              • With one server stopped, its subtree is marked disconnected with a last-updated
                timestamp
                , other machines stay live, and nothing renders blank or silently stale.
              • A human approves a real gate from the client through Phase 6's capability path.
              • No dangerouslySetInnerHTML on agent output; a restrictive CSP; explicit origin rules. The
                client holds credentials for N servers, which makes XSS a credential-theft path rather than a
                defacement one.
              • Tests for this phase.

              Acceptance Criteria

              • Criterion 3: correct live status on every row including the structured gate content.
              • Criterion 7: two machines in one tree, independently live.
              • Criterion 8: one server stopped, subtree disconnected with a timestamp, others unaffected.
              • Criterion 9b: a real gate approved from the client, with session id, machine and timestamp in
                status.yaml.
              • Criterion 15's scenario: revoking one machine's token fails that subtree closed and leaves
                others unaffected.
              • A grep asserts no dangerouslySetInnerHTML in the app.
              • Build and tests pass.

              Test Plan

              Unit and component: status derivation for every state; the porch-wins reconciliation; disconnected
              rendering.

              E2E under Playwright against two live servers: both trees correct, one stopped, the subtree marked,
              a gate approved.



              Architect notes

              Dependencies are satisfied. Phase 6 (agent-farm/lib/approval-capability.ts) and phase 7
              (agent-farm/lib/machine-credentials.ts) are on main. Phase 9 is on mainpartial — items
              3 and 4 of #179 (an architect thread in production; a thread surviving a server restart with
              context) are being run under #219 in parallel with this work. Nothing in phase 11 blocks on them.

              The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright. Follow that app's
              conventions rather than inventing new ones.

              A green test suite cannot detect design infidelity. This repo has shipped a client that passed
              127 client tests, 3,394 server tests and 15/15 Playwright with correct tokens and correct colour
              discipline, and was unusable — it had dropped every label prefix, the header bar, and rendered
              idle sparklines as invisible dots (#112). Component tests that assert "the name renders" pass
              happily while the thing that made the name legible is gone. Open the running client and look at
              it before you call any of this done.

              A pinned t3 server is already running on 127.0.0.1:3799 at commit 082e6ea52186, started
              with T3_NODE=/opt/homebrew/bin/node node tools/t3-server/t3-server.mjs start. T3_NODE must be
              an absolute interpreter path; the harness refuses to inherit its Node from PATH and reports
              NO_INTERPRETER: could not check rather than guessing. Re-verify the pin yourself with status.

              The two-server criteria need a second server. Criterion 7 (two machines in one tree) and
              criterion 8 (one stopped, its subtree disconnected with a timestamp) cannot be satisfied against a
              single server, and a single-server approximation of them is not evidence. Work out how to stand up
              the second instance early rather than at the end.

              On honest degradation, which is the deliverable most easily faked. "Disconnected" must be
              distinguishable from "connected and idle" and from "connected and empty". A subtree that renders
              blank, or renders its last known state without saying when that state is from, has failed
              criterion 8 regardless of what the test asserts. This repo's standing rule is that "I could not
              tell" must never be spelled the same way as "no" — three separate defects of exactly that shape
              landed in one day (#214, #216, #217). The last-updated timestamp is what makes the difference
              observable, so it is not decoration.

              Where porch and t3code disagree, porch wins. Titles, pins and activity entries from t3code are
              display projections, never a source of truth.

              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

                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

                  Spec 146 phase 11: codev-client tree and live status #220

                  Description

                  @pseudoseed

                  Spec 146 phase 11. This is the first phase of the initiative that produces something a human can
                  look at.
                  Phases 1-9 are plumbing: the contract, the transport, the driver, delivery semantics,
                  the state service, approvals, security, thread identity, and afx parity. All of that is on main
                  and none of it is visible. This phase is the payoff, and it should be treated as the priority it
                  is.

                  The plan section is reproduced below verbatim so it is not fetched by path.


                  Phase 11: codev-client tree and live status

                  Dependencies: Phase 6, Phase 7, Phase 9

                  Objective

                  The left sidebar tree: machine, workspace, architects, that architect's builders, with correct live
                  status on every row — including a builder blocked on a gate showing #128's structured question, not
                  only a gate name. Multi-machine and honest degradation land here too, because a tree that cannot
                  say "disconnected" is worse than no tree.

                  The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright.

                  Files to Create / Modify

                  • apps/client/package.json, vite.config.ts, tsconfig.json
                  • apps/client/src/tree/ — the workspace tree.
                  • apps/client/src/connection/ — per-machine connection, one per server.
                  • apps/client/src/status/ — row status derivation.
                  • apps/client/src/gate/ — structured gate rendering and approval.
                  • apps/client/e2e/

                  Deliverables

                  • The tree renders machine, workspace, architects, and each architect's builders.
                  • Every row carries live status: working, turning, blocked on a named gate, or settled.
                  • A blocked builder shows its structured question and choices without navigation, and is
                    visually distinct from a settled one. A gate name alone does not satisfy this.
                  • Where porch and t3code disagree, porch wins and the client shows porch's value. Titles,
                    pins and activity entries are display projections, never a source of truth.
                  • A thread with no porch record renders as unmanaged, not hidden.
                  • One client connects to more than one machine's server at once, each independently live.
                  • With one server stopped, its subtree is marked disconnected with a last-updated
                    timestamp
                    , other machines stay live, and nothing renders blank or silently stale.
                  • A human approves a real gate from the client through Phase 6's capability path.
                  • No dangerouslySetInnerHTML on agent output; a restrictive CSP; explicit origin rules. The
                    client holds credentials for N servers, which makes XSS a credential-theft path rather than a
                    defacement one.
                  • Tests for this phase.

                  Acceptance Criteria

                  • Criterion 3: correct live status on every row including the structured gate content.
                  • Criterion 7: two machines in one tree, independently live.
                  • Criterion 8: one server stopped, subtree disconnected with a timestamp, others unaffected.
                  • Criterion 9b: a real gate approved from the client, with session id, machine and timestamp in
                    status.yaml.
                  • Criterion 15's scenario: revoking one machine's token fails that subtree closed and leaves
                    others unaffected.
                  • A grep asserts no dangerouslySetInnerHTML in the app.
                  • Build and tests pass.

                  Test Plan

                  Unit and component: status derivation for every state; the porch-wins reconciliation; disconnected
                  rendering.

                  E2E under Playwright against two live servers: both trees correct, one stopped, the subtree marked,
                  a gate approved.



                  Architect notes

                  Dependencies are satisfied. Phase 6 (agent-farm/lib/approval-capability.ts) and phase 7
                  (agent-farm/lib/machine-credentials.ts) are on main. Phase 9 is on mainpartial — items
                  3 and 4 of #179 (an architect thread in production; a thread surviving a server restart with
                  context) are being run under #219 in parallel with this work. Nothing in phase 11 blocks on them.

                  The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright. Follow that app's
                  conventions rather than inventing new ones.

                  A green test suite cannot detect design infidelity. This repo has shipped a client that passed
                  127 client tests, 3,394 server tests and 15/15 Playwright with correct tokens and correct colour
                  discipline, and was unusable — it had dropped every label prefix, the header bar, and rendered
                  idle sparklines as invisible dots (#112). Component tests that assert "the name renders" pass
                  happily while the thing that made the name legible is gone. Open the running client and look at
                  it before you call any of this done.

                  A pinned t3 server is already running on 127.0.0.1:3799 at commit 082e6ea52186, started
                  with T3_NODE=/opt/homebrew/bin/node node tools/t3-server/t3-server.mjs start. T3_NODE must be
                  an absolute interpreter path; the harness refuses to inherit its Node from PATH and reports
                  NO_INTERPRETER: could not check rather than guessing. Re-verify the pin yourself with status.

                  The two-server criteria need a second server. Criterion 7 (two machines in one tree) and
                  criterion 8 (one stopped, its subtree disconnected with a timestamp) cannot be satisfied against a
                  single server, and a single-server approximation of them is not evidence. Work out how to stand up
                  the second instance early rather than at the end.

                  On honest degradation, which is the deliverable most easily faked. "Disconnected" must be
                  distinguishable from "connected and idle" and from "connected and empty". A subtree that renders
                  blank, or renders its last known state without saying when that state is from, has failed
                  criterion 8 regardless of what the test asserts. This repo's standing rule is that "I could not
                  tell" must never be spelled the same way as "no" — three separate defects of exactly that shape
                  landed in one day (#214, #216, #217). The last-updated timestamp is what makes the difference
                  observable, so it is not decoration.

                  Where porch and t3code disagree, porch wins. Titles, pins and activity entries from t3code are
                  display projections, never a source of truth.

                  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

                    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

                      Spec 146 phase 11: codev-client tree and live status #220

                      Description

                      @pseudoseed

                      Spec 146 phase 11. This is the first phase of the initiative that produces something a human can
                      look at.
                      Phases 1-9 are plumbing: the contract, the transport, the driver, delivery semantics,
                      the state service, approvals, security, thread identity, and afx parity. All of that is on main
                      and none of it is visible. This phase is the payoff, and it should be treated as the priority it
                      is.

                      The plan section is reproduced below verbatim so it is not fetched by path.


                      Phase 11: codev-client tree and live status

                      Dependencies: Phase 6, Phase 7, Phase 9

                      Objective

                      The left sidebar tree: machine, workspace, architects, that architect's builders, with correct live
                      status on every row — including a builder blocked on a gate showing #128's structured question, not
                      only a gate name. Multi-machine and honest degradation land here too, because a tree that cannot
                      say "disconnected" is worse than no tree.

                      The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright.

                      Files to Create / Modify

                      • apps/client/package.json, vite.config.ts, tsconfig.json
                      • apps/client/src/tree/ — the workspace tree.
                      • apps/client/src/connection/ — per-machine connection, one per server.
                      • apps/client/src/status/ — row status derivation.
                      • apps/client/src/gate/ — structured gate rendering and approval.
                      • apps/client/e2e/

                      Deliverables

                      • The tree renders machine, workspace, architects, and each architect's builders.
                      • Every row carries live status: working, turning, blocked on a named gate, or settled.
                      • A blocked builder shows its structured question and choices without navigation, and is
                        visually distinct from a settled one. A gate name alone does not satisfy this.
                      • Where porch and t3code disagree, porch wins and the client shows porch's value. Titles,
                        pins and activity entries are display projections, never a source of truth.
                      • A thread with no porch record renders as unmanaged, not hidden.
                      • One client connects to more than one machine's server at once, each independently live.
                      • With one server stopped, its subtree is marked disconnected with a last-updated
                        timestamp
                        , other machines stay live, and nothing renders blank or silently stale.
                      • A human approves a real gate from the client through Phase 6's capability path.
                      • No dangerouslySetInnerHTML on agent output; a restrictive CSP; explicit origin rules. The
                        client holds credentials for N servers, which makes XSS a credential-theft path rather than a
                        defacement one.
                      • Tests for this phase.

                      Acceptance Criteria

                      • Criterion 3: correct live status on every row including the structured gate content.
                      • Criterion 7: two machines in one tree, independently live.
                      • Criterion 8: one server stopped, subtree disconnected with a timestamp, others unaffected.
                      • Criterion 9b: a real gate approved from the client, with session id, machine and timestamp in
                        status.yaml.
                      • Criterion 15's scenario: revoking one machine's token fails that subtree closed and leaves
                        others unaffected.
                      • A grep asserts no dangerouslySetInnerHTML in the app.
                      • Build and tests pass.

                      Test Plan

                      Unit and component: status derivation for every state; the porch-wins reconciliation; disconnected
                      rendering.

                      E2E under Playwright against two live servers: both trees correct, one stopped, the subtree marked,
                      a gate approved.



                      Architect notes

                      Dependencies are satisfied. Phase 6 (agent-farm/lib/approval-capability.ts) and phase 7
                      (agent-farm/lib/machine-credentials.ts) are on main. Phase 9 is on mainpartial — items
                      3 and 4 of #179 (an architect thread in production; a thread surviving a server restart with
                      context) are being run under #219 in parallel with this work. Nothing in phase 11 blocks on them.

                      The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright. Follow that app's
                      conventions rather than inventing new ones.

                      A green test suite cannot detect design infidelity. This repo has shipped a client that passed
                      127 client tests, 3,394 server tests and 15/15 Playwright with correct tokens and correct colour
                      discipline, and was unusable — it had dropped every label prefix, the header bar, and rendered
                      idle sparklines as invisible dots (#112). Component tests that assert "the name renders" pass
                      happily while the thing that made the name legible is gone. Open the running client and look at
                      it before you call any of this done.

                      A pinned t3 server is already running on 127.0.0.1:3799 at commit 082e6ea52186, started
                      with T3_NODE=/opt/homebrew/bin/node node tools/t3-server/t3-server.mjs start. T3_NODE must be
                      an absolute interpreter path; the harness refuses to inherit its Node from PATH and reports
                      NO_INTERPRETER: could not check rather than guessing. Re-verify the pin yourself with status.

                      The two-server criteria need a second server. Criterion 7 (two machines in one tree) and
                      criterion 8 (one stopped, its subtree disconnected with a timestamp) cannot be satisfied against a
                      single server, and a single-server approximation of them is not evidence. Work out how to stand up
                      the second instance early rather than at the end.

                      On honest degradation, which is the deliverable most easily faked. "Disconnected" must be
                      distinguishable from "connected and idle" and from "connected and empty". A subtree that renders
                      blank, or renders its last known state without saying when that state is from, has failed
                      criterion 8 regardless of what the test asserts. This repo's standing rule is that "I could not
                      tell" must never be spelled the same way as "no" — three separate defects of exactly that shape
                      landed in one day (#214, #216, #217). The last-updated timestamp is what makes the difference
                      observable, so it is not decoration.

                      Where porch and t3code disagree, porch wins. Titles, pins and activity entries from t3code are
                      display projections, never a source of truth.

                      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

                        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

                          Spec 146 phase 11: codev-client tree and live status #220

                          Description

                          @pseudoseed

                          Spec 146 phase 11. This is the first phase of the initiative that produces something a human can
                          look at.
                          Phases 1-9 are plumbing: the contract, the transport, the driver, delivery semantics,
                          the state service, approvals, security, thread identity, and afx parity. All of that is on main
                          and none of it is visible. This phase is the payoff, and it should be treated as the priority it
                          is.

                          The plan section is reproduced below verbatim so it is not fetched by path.


                          Phase 11: codev-client tree and live status

                          Dependencies: Phase 6, Phase 7, Phase 9

                          Objective

                          The left sidebar tree: machine, workspace, architects, that architect's builders, with correct live
                          status on every row — including a builder blocked on a gate showing #128's structured question, not
                          only a gate name. Multi-machine and honest degradation land here too, because a tree that cannot
                          say "disconnected" is worse than no tree.

                          The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright.

                          Files to Create / Modify

                          • apps/client/package.json, vite.config.ts, tsconfig.json
                          • apps/client/src/tree/ — the workspace tree.
                          • apps/client/src/connection/ — per-machine connection, one per server.
                          • apps/client/src/status/ — row status derivation.
                          • apps/client/src/gate/ — structured gate rendering and approval.
                          • apps/client/e2e/

                          Deliverables

                          • The tree renders machine, workspace, architects, and each architect's builders.
                          • Every row carries live status: working, turning, blocked on a named gate, or settled.
                          • A blocked builder shows its structured question and choices without navigation, and is
                            visually distinct from a settled one. A gate name alone does not satisfy this.
                          • Where porch and t3code disagree, porch wins and the client shows porch's value. Titles,
                            pins and activity entries are display projections, never a source of truth.
                          • A thread with no porch record renders as unmanaged, not hidden.
                          • One client connects to more than one machine's server at once, each independently live.
                          • With one server stopped, its subtree is marked disconnected with a last-updated
                            timestamp
                            , other machines stay live, and nothing renders blank or silently stale.
                          • A human approves a real gate from the client through Phase 6's capability path.
                          • No dangerouslySetInnerHTML on agent output; a restrictive CSP; explicit origin rules. The
                            client holds credentials for N servers, which makes XSS a credential-theft path rather than a
                            defacement one.
                          • Tests for this phase.

                          Acceptance Criteria

                          • Criterion 3: correct live status on every row including the structured gate content.
                          • Criterion 7: two machines in one tree, independently live.
                          • Criterion 8: one server stopped, subtree disconnected with a timestamp, others unaffected.
                          • Criterion 9b: a real gate approved from the client, with session id, machine and timestamp in
                            status.yaml.
                          • Criterion 15's scenario: revoking one machine's token fails that subtree closed and leaves
                            others unaffected.
                          • A grep asserts no dangerouslySetInnerHTML in the app.
                          • Build and tests pass.

                          Test Plan

                          Unit and component: status derivation for every state; the porch-wins reconciliation; disconnected
                          rendering.

                          E2E under Playwright against two live servers: both trees correct, one stopped, the subtree marked,
                          a gate approved.



                          Architect notes

                          Dependencies are satisfied. Phase 6 (agent-farm/lib/approval-capability.ts) and phase 7
                          (agent-farm/lib/machine-credentials.ts) are on main. Phase 9 is on mainpartial — items
                          3 and 4 of #179 (an architect thread in production; a thread surviving a server restart with
                          context) are being run under #219 in parallel with this work. Nothing in phase 11 blocks on them.

                          The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright. Follow that app's
                          conventions rather than inventing new ones.

                          A green test suite cannot detect design infidelity. This repo has shipped a client that passed
                          127 client tests, 3,394 server tests and 15/15 Playwright with correct tokens and correct colour
                          discipline, and was unusable — it had dropped every label prefix, the header bar, and rendered
                          idle sparklines as invisible dots (#112). Component tests that assert "the name renders" pass
                          happily while the thing that made the name legible is gone. Open the running client and look at
                          it before you call any of this done.

                          A pinned t3 server is already running on 127.0.0.1:3799 at commit 082e6ea52186, started
                          with T3_NODE=/opt/homebrew/bin/node node tools/t3-server/t3-server.mjs start. T3_NODE must be
                          an absolute interpreter path; the harness refuses to inherit its Node from PATH and reports
                          NO_INTERPRETER: could not check rather than guessing. Re-verify the pin yourself with status.

                          The two-server criteria need a second server. Criterion 7 (two machines in one tree) and
                          criterion 8 (one stopped, its subtree disconnected with a timestamp) cannot be satisfied against a
                          single server, and a single-server approximation of them is not evidence. Work out how to stand up
                          the second instance early rather than at the end.

                          On honest degradation, which is the deliverable most easily faked. "Disconnected" must be
                          distinguishable from "connected and idle" and from "connected and empty". A subtree that renders
                          blank, or renders its last known state without saying when that state is from, has failed
                          criterion 8 regardless of what the test asserts. This repo's standing rule is that "I could not
                          tell" must never be spelled the same way as "no" — three separate defects of exactly that shape
                          landed in one day (#214, #216, #217). The last-updated timestamp is what makes the difference
                          observable, so it is not decoration.

                          Where porch and t3code disagree, porch wins. Titles, pins and activity entries from t3code are
                          display projections, never a source of truth.

                          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

                            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

                              Spec 146 phase 11: codev-client tree and live status #220

                              Description

                              @pseudoseed

                              Spec 146 phase 11. This is the first phase of the initiative that produces something a human can
                              look at.
                              Phases 1-9 are plumbing: the contract, the transport, the driver, delivery semantics,
                              the state service, approvals, security, thread identity, and afx parity. All of that is on main
                              and none of it is visible. This phase is the payoff, and it should be treated as the priority it
                              is.

                              The plan section is reproduced below verbatim so it is not fetched by path.


                              Phase 11: codev-client tree and live status

                              Dependencies: Phase 6, Phase 7, Phase 9

                              Objective

                              The left sidebar tree: machine, workspace, architects, that architect's builders, with correct live
                              status on every row — including a builder blocked on a gate showing #128's structured question, not
                              only a gate name. Multi-machine and honest degradation land here too, because a tree that cannot
                              say "disconnected" is worse than no tree.

                              The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright.

                              Files to Create / Modify

                              • apps/client/package.json, vite.config.ts, tsconfig.json
                              • apps/client/src/tree/ — the workspace tree.
                              • apps/client/src/connection/ — per-machine connection, one per server.
                              • apps/client/src/status/ — row status derivation.
                              • apps/client/src/gate/ — structured gate rendering and approval.
                              • apps/client/e2e/

                              Deliverables

                              • The tree renders machine, workspace, architects, and each architect's builders.
                              • Every row carries live status: working, turning, blocked on a named gate, or settled.
                              • A blocked builder shows its structured question and choices without navigation, and is
                                visually distinct from a settled one. A gate name alone does not satisfy this.
                              • Where porch and t3code disagree, porch wins and the client shows porch's value. Titles,
                                pins and activity entries are display projections, never a source of truth.
                              • A thread with no porch record renders as unmanaged, not hidden.
                              • One client connects to more than one machine's server at once, each independently live.
                              • With one server stopped, its subtree is marked disconnected with a last-updated
                                timestamp
                                , other machines stay live, and nothing renders blank or silently stale.
                              • A human approves a real gate from the client through Phase 6's capability path.
                              • No dangerouslySetInnerHTML on agent output; a restrictive CSP; explicit origin rules. The
                                client holds credentials for N servers, which makes XSS a credential-theft path rather than a
                                defacement one.
                              • Tests for this phase.

                              Acceptance Criteria

                              • Criterion 3: correct live status on every row including the structured gate content.
                              • Criterion 7: two machines in one tree, independently live.
                              • Criterion 8: one server stopped, subtree disconnected with a timestamp, others unaffected.
                              • Criterion 9b: a real gate approved from the client, with session id, machine and timestamp in
                                status.yaml.
                              • Criterion 15's scenario: revoking one machine's token fails that subtree closed and leaves
                                others unaffected.
                              • A grep asserts no dangerouslySetInnerHTML in the app.
                              • Build and tests pass.

                              Test Plan

                              Unit and component: status derivation for every state; the porch-wins reconciliation; disconnected
                              rendering.

                              E2E under Playwright against two live servers: both trees correct, one stopped, the subtree marked,
                              a gate approved.



                              Architect notes

                              Dependencies are satisfied. Phase 6 (agent-farm/lib/approval-capability.ts) and phase 7
                              (agent-farm/lib/machine-credentials.ts) are on main. Phase 9 is on mainpartial — items
                              3 and 4 of #179 (an architect thread in production; a thread surviving a server restart with
                              context) are being run under #219 in parallel with this work. Nothing in phase 11 blocks on them.

                              The stack matches apps/v2: React 19, Vite 6, Vitest 4, Playwright. Follow that app's
                              conventions rather than inventing new ones.

                              A green test suite cannot detect design infidelity. This repo has shipped a client that passed
                              127 client tests, 3,394 server tests and 15/15 Playwright with correct tokens and correct colour
                              discipline, and was unusable — it had dropped every label prefix, the header bar, and rendered
                              idle sparklines as invisible dots (#112). Component tests that assert "the name renders" pass
                              happily while the thing that made the name legible is gone. Open the running client and look at
                              it before you call any of this done.

                              A pinned t3 server is already running on 127.0.0.1:3799 at commit 082e6ea52186, started
                              with T3_NODE=/opt/homebrew/bin/node node tools/t3-server/t3-server.mjs start. T3_NODE must be
                              an absolute interpreter path; the harness refuses to inherit its Node from PATH and reports
                              NO_INTERPRETER: could not check rather than guessing. Re-verify the pin yourself with status.

                              The two-server criteria need a second server. Criterion 7 (two machines in one tree) and
                              criterion 8 (one stopped, its subtree disconnected with a timestamp) cannot be satisfied against a
                              single server, and a single-server approximation of them is not evidence. Work out how to stand up
                              the second instance early rather than at the end.

                              On honest degradation, which is the deliverable most easily faked. "Disconnected" must be
                              distinguishable from "connected and idle" and from "connected and empty". A subtree that renders
                              blank, or renders its last known state without saying when that state is from, has failed
                              criterion 8 regardless of what the test asserts. This repo's standing rule is that "I could not
                              tell" must never be spelled the same way as "no" — three separate defects of exactly that shape
                              landed in one day (#214, #216, #217). The last-updated timestamp is what makes the difference
                              observable, so it is not decoration.

                              Where porch and t3code disagree, porch wins. Titles, pins and activity entries from t3code are
                              display projections, never a source of truth.

                              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

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions