# PR 23789 — omitted protocol metadata, before / after

Date: 2026-10-22 UTC. Host fs-31. No source changes, commits, pushes, merge, comments, or posted reviews.

Head: [c502579298](https://git.cafe/pingdotgg/t3code/commit/c502579298f719c4346f48ff75f3b7d896ba17c4).
Merge-base: [044f07257c](https://git.cafe/pingdotgg/t3code/commit/044f07257c9684ae4543bd1e1ebf9c394e9e3830).

## Scope and method

A controlled HTTP descriptor fixture, not a full production T3 server, served the exact descriptor below with orchestrationProtocolVersion absent. Its advertised server version is 0.0.45. The actual unmodified source CLI entrypoint ran at both revisions, with explicit --base-dir, HOME, T3CODE_HOME, and XDG directories confined to /tmp/ev-23789. The fixture does not implement token exchange; no exchange acceptance is claimed. No real T3 database was accessed. No Tailscale command was invoked. The read-only reviews traced Tailscale ordering and all discovery paths; this runtime row tests direct discovery and local auth writes.

Each fresh home initially held only userdata/server-runtime.json and an empty os-home. Existing-state homes were separate copies of the successful before/fresh home (one pairing link), with their runtime state refreshed before the initial inventory. File byte hashes and auth table row counts were captured before and after. No database rows, signing-key bytes, pairing URLs, credentials, or QR code pixels are published. Whole QR output is discarded, since it encodes the credential.

Runtime: real Node 26.12.1 binary, Linux x64. An initial run through the Vite+ node shim installed a Node runtime into the isolated OS home. That harness-only run was discarded, its server stopped and homes removed; the published result reruns through the installed binary directly. Both fixture processes were owned by this driver, their port-owner PIDs recorded after listening, and /proc/<pid>/cwd verified before termination. Initial discarded fixture: PID 1568317, port 38571, cwd /tmp/ev-23789; successful fixture follows below. No server remains running.

## Result

| Descriptor omits protocol metadata | Before (merge-base) | After (head) |
| --- | --- | --- |
| Current CLI, fresh isolated home | Exit 0; token issued; creates environment-id, secrets/server-signing-key.bin, statev2.sqlite; auth_pairing_links 0→1 | Exit 1; no token; defaults to protocol 1, refuses against CLI protocol 2; no files created or changed |
| Same descriptor, existing isolated state (control) | Exit 0; token issued; statev2.sqlite hash changes; auth_pairing_links 1→2 | Exit 1; no token; every file hash unchanged; auth_pairing_links stays 1 |

After refusal includes both versions and `npx t3@0.0.45 pair`. User-supplied flags must be retained when rerunning. A hypothetical V2 server that omits the field would also be classified V1; production V2 descriptor constructors always emit it, and both reviewers confirmed it was present from V2 introduction.

## Independent reviews

- A: Codex / gpt-6.1-sol — VERDICT: MERGE. Full diff and surrounding discovery/config/auth paths reviewed. Compatibility guard precedes DB migration, secrets, environment ID and Tailscale writes; discovery failures do not reach minting. No pairing acceptance/scope/grant changes. Static review and diff check; no runtime suite executed by A.
- B: Claude Agent / claude-opus-5-5 — VERDICT: MERGE. Full diff and history traced; missing field is the established V1 default, V2 producers always include it. No auth acceptance/grant change. Focused pair.test.ts passed 14/14. Nonblocking: matching-version command omits original flags; unpublished versions may not resolve on npm. No fixes applied.

No correction to the existing PR-body runtime claims was found. This evidence adds the omitted-field case; it does not independently repeat the full real V1/V2 server exchange audit. No formal forge review was posted.

Driver SHA-256: `4c008957f981f4a2cb7812cd5067f23fa2ccf8b34861975e6e26a5ceb96e1226`.

## Sanitized transcript and file inventories

```json
{
  "descriptor": {
    "environmentId": "evidence-23789",
    "label": "omitted-protocol-fixture",
    "platform": {
      "os": "linux",
      "arch": "x64"
    },
    "serverVersion": "0.0.45",
    "capabilities": {
      "repositoryIdentity": true
    }
  },
  "port_owner": "LISTEN 0      5      127.0.0.1:34713 0.0.0.0:* users:((\"python3\",pid=1568655,fd=3))",
  "cwd": "/tmp/ev-23789",
  "results": [
    {
      "revision": "before",
      "variant": "fresh",
      "command": [
        "/home/ubuntu/.local/share/vite-plus/js_runtime/node/26.12.1/bin/node",
        "/home/ubuntu/wt/pr-23789-before/apps/server/src/bin.ts",
        "pair",
        "--base-dir",
        "/tmp/ev-23789/before-fresh"
      ],
      "exit": 0,
      "token_issued": true,
      "transcript": "Pairing with omitted-protocol-fixture (http://127.0.0.1:34713).\nExpires: 2026-10-22T20:01:03.264Z\nNote: This URL is only reachable from this machine. Re-run with --tailscale, or restart the server with a reachable --host.\n[Pairing URL, token, and complete QR code REDACTED]",
      "before": {
        "userdata/server-runtime.json": {
          "size": 144,
          "sha256": "c50fc8d1a7048f10bea7ef62b6ae744357b754d0a965d8b5f63c1caf1c725b7b"
        }
      },
      "after": {
        "userdata/environment-id": {
          "size": 37,
          "sha256": "1c54acf389773124c5ea74a1280dd2f31d777007b8db41717396750a273e2251"
        },
        "userdata/secrets/server-signing-key.bin": {
          "size": 32,
          "sha256": "0a0b9a44a1cd5ae8a6f83b80f1c8bb4bcd68c52bbc8dca92c4596c287c5ecf37"
        },
        "userdata/server-runtime.json": {
          "size": 144,
          "sha256": "c50fc8d1a7048f10bea7ef62b6ae744357b754d0a965d8b5f63c1caf1c725b7b"
        },
        "userdata/statev2.sqlite": {
          "size": 868352,
          "sha256": "9dc7fc276c38c2004ae6caf69a89b8c8bcdb6a7d9abafe1119f1eb91b1f259a0"
        }
      },
      "new_files": [
        "userdata/environment-id",
        "userdata/secrets/server-signing-key.bin",
        "userdata/statev2.sqlite"
      ],
      "changed_files": [],
      "db_before": null,
      "db_after": {
        "auth_pairing_links": 1,
        "auth_sessions": 0
      }
    },
    {
      "revision": "after",
      "variant": "fresh",
      "command": [
        "/home/ubuntu/.local/share/vite-plus/js_runtime/node/26.12.1/bin/node",
        "/home/ubuntu/wt/pr-23789/apps/server/src/bin.ts",
        "pair",
        "--base-dir",
        "/tmp/ev-23789/after-fresh"
      ],
      "exit": 1,
      "token_issued": false,
      "transcript": "[19:56:07.785] ERROR (#2): IncompatibleServerProtocolError: The running T3 Code server (0.0.45) speaks orchestration protocol 1, but this CLI speaks protocol 2.\nPair with the matching CLI instead: `npx t3@0.0.45 pair`.\n    at file:///home/ubuntu/wt/pr-23789/apps/server/src/cli/pair.ts:514:23\n",
      "before": {
        "userdata/server-runtime.json": {
          "size": 144,
          "sha256": "c50fc8d1a7048f10bea7ef62b6ae744357b754d0a965d8b5f63c1caf1c725b7b"
        }
      },
      "after": {
        "userdata/server-runtime.json": {
          "size": 144,
          "sha256": "c50fc8d1a7048f10bea7ef62b6ae744357b754d0a965d8b5f63c1caf1c725b7b"
        }
      },
      "new_files": [],
      "changed_files": [],
      "db_before": null,
      "db_after": null
    },
    {
      "revision": "before",
      "variant": "existing",
      "command": [
        "/home/ubuntu/.local/share/vite-plus/js_runtime/node/26.12.1/bin/node",
        "/home/ubuntu/wt/pr-23789-before/apps/server/src/bin.ts",
        "pair",
        "--base-dir",
        "/tmp/ev-23789/before-existing"
      ],
      "exit": 0,
      "token_issued": true,
      "transcript": "Pairing with omitted-protocol-fixture (http://127.0.0.1:34713).\nExpires: 2026-10-22T20:01:12.226Z\nNote: This URL is only reachable from this machine. Re-run with --tailscale, or restart the server with a reachable --host.\n[Pairing URL, token, and complete QR code REDACTED]",
      "before": {
        "userdata/environment-id": {
          "size": 37,
          "sha256": "1c54acf389773124c5ea74a1280dd2f31d777007b8db41717396750a273e2251"
        },
        "userdata/secrets/server-signing-key.bin": {
          "size": 32,
          "sha256": "0a0b9a44a1cd5ae8a6f83b80f1c8bb4bcd68c52bbc8dca92c4596c287c5ecf37"
        },
        "userdata/server-runtime.json": {
          "size": 144,
          "sha256": "c50fc8d1a7048f10bea7ef62b6ae744357b754d0a965d8b5f63c1caf1c725b7b"
        },
        "userdata/statev2.sqlite": {
          "size": 868352,
          "sha256": "9dc7fc276c38c2004ae6caf69a89b8c8bcdb6a7d9abafe1119f1eb91b1f259a0"
        },
        "userdata/statev2.sqlite-shm": {
          "size": 32768,
          "sha256": "fd4c9fda9cd3f9ae7c962b0ddf37232294d55580e1aa165aa06129b8549389eb"
        },
        "userdata/statev2.sqlite-wal": {
          "size": 0,
          "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
        }
      },
      "after": {
        "userdata/environment-id": {
          "size": 37,
          "sha256": "1c54acf389773124c5ea74a1280dd2f31d777007b8db41717396750a273e2251"
        },
        "userdata/secrets/server-signing-key.bin": {
          "size": 32,
          "sha256": "0a0b9a44a1cd5ae8a6f83b80f1c8bb4bcd68c52bbc8dca92c4596c287c5ecf37"
        },
        "userdata/server-runtime.json": {
          "size": 144,
          "sha256": "c50fc8d1a7048f10bea7ef62b6ae744357b754d0a965d8b5f63c1caf1c725b7b"
        },
        "userdata/statev2.sqlite": {
          "size": 868352,
          "sha256": "c534605aa2e4f5c3aec428805e9cfae686f70e9cf1e4458cce95aeec6ea64dc6"
        }
      },
      "new_files": [],
      "changed_files": [
        "userdata/statev2.sqlite"
      ],
      "db_before": {
        "auth_pairing_links": 1,
        "auth_sessions": 0
      },
      "db_after": {
        "auth_pairing_links": 2,
        "auth_sessions": 0
      }
    },
    {
      "revision": "after",
      "variant": "existing",
      "command": [
        "/home/ubuntu/.local/share/vite-plus/js_runtime/node/26.12.1/bin/node",
        "/home/ubuntu/wt/pr-23789/apps/server/src/bin.ts",
        "pair",
        "--base-dir",
        "/tmp/ev-23789/after-existing"
      ],
      "exit": 1,
      "token_issued": false,
      "transcript": "[19:56:16.631] ERROR (#2): IncompatibleServerProtocolError: The running T3 Code server (0.0.45) speaks orchestration protocol 1, but this CLI speaks protocol 2.\nPair with the matching CLI instead: `npx t3@0.0.45 pair`.\n    at file:///home/ubuntu/wt/pr-23789/apps/server/src/cli/pair.ts:514:23\n",
      "before": {
        "userdata/environment-id": {
          "size": 37,
          "sha256": "1c54acf389773124c5ea74a1280dd2f31d777007b8db41717396750a273e2251"
        },
        "userdata/secrets/server-signing-key.bin": {
          "size": 32,
          "sha256": "0a0b9a44a1cd5ae8a6f83b80f1c8bb4bcd68c52bbc8dca92c4596c287c5ecf37"
        },
        "userdata/server-runtime.json": {
          "size": 144,
          "sha256": "c50fc8d1a7048f10bea7ef62b6ae744357b754d0a965d8b5f63c1caf1c725b7b"
        },
        "userdata/statev2.sqlite": {
          "size": 868352,
          "sha256": "9dc7fc276c38c2004ae6caf69a89b8c8bcdb6a7d9abafe1119f1eb91b1f259a0"
        },
        "userdata/statev2.sqlite-shm": {
          "size": 32768,
          "sha256": "fd4c9fda9cd3f9ae7c962b0ddf37232294d55580e1aa165aa06129b8549389eb"
        },
        "userdata/statev2.sqlite-wal": {
          "size": 0,
          "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
        }
      },
      "after": {
        "userdata/environment-id": {
          "size": 37,
          "sha256": "1c54acf389773124c5ea74a1280dd2f31d777007b8db41717396750a273e2251"
        },
        "userdata/secrets/server-signing-key.bin": {
          "size": 32,
          "sha256": "0a0b9a44a1cd5ae8a6f83b80f1c8bb4bcd68c52bbc8dca92c4596c287c5ecf37"
        },
        "userdata/server-runtime.json": {
          "size": 144,
          "sha256": "c50fc8d1a7048f10bea7ef62b6ae744357b754d0a965d8b5f63c1caf1c725b7b"
        },
        "userdata/statev2.sqlite": {
          "size": 868352,
          "sha256": "9dc7fc276c38c2004ae6caf69a89b8c8bcdb6a7d9abafe1119f1eb91b1f259a0"
        },
        "userdata/statev2.sqlite-shm": {
          "size": 32768,
          "sha256": "fd4c9fda9cd3f9ae7c962b0ddf37232294d55580e1aa165aa06129b8549389eb"
        },
        "userdata/statev2.sqlite-wal": {
          "size": 0,
          "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
        }
      },
      "new_files": [],
      "changed_files": [],
      "db_before": {
        "auth_pairing_links": 1,
        "auth_sessions": 0
      },
      "db_after": {
        "auth_pairing_links": 1,
        "auth_sessions": 0
      }
    }
  ]
}
```

## Exact driver

```python
import hashlib, http.server, json, os, pathlib, re, shutil, sqlite3, subprocess, sys, threading, time

ROOT = pathlib.Path('/tmp/ev-23789')
DESCRIPTOR = dict(environmentId='evidence-23789', label='omitted-protocol-fixture', platform=dict(os='linux', arch='x64'), serverVersion='0.0.45', capabilities=dict(repositoryIdentity=True))

if len(sys.argv) > 1 and sys.argv[1] == '--server':
    class Handler(http.server.BaseHTTPRequestHandler):
        def do_GET(self):
            if self.path != '/.well-known/t3/environment':
                self.send_error(404)
                return
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps(DESCRIPTOR).encode())
        def log_message(self, *args):
            pass
    server = http.server.HTTPServer(('127.0.0.1', 0), Handler)
    (ROOT / 'server-ready.json').write_text(json.dumps(dict(pid=os.getpid(), port=server.server_port)))
    server.serve_forever()
    sys.exit(0)

def inventory(home):
    return {str(p.relative_to(home)): dict(size=p.stat().st_size, sha256=hashlib.sha256(p.read_bytes()).hexdigest()) for p in sorted(home.rglob('*')) if p.is_file()}

def db_summary(home):
    db = home / 'userdata/statev2.sqlite'
    if not db.exists():
        return None
    conn = sqlite3.connect(f'file:{db}?mode=ro', uri=True)
    try:
        tables = [r[0] for r in conn.execute("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%auth%'")]
        return {t: conn.execute('SELECT COUNT(*) FROM "' + t.replace('"','""') + '"').fetchone()[0] for t in tables}
    finally:
        conn.close()

server = subprocess.Popen([sys.executable, str(ROOT / 'driver.py'), '--server'], cwd=ROOT, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
results = []
try:
    for _ in range(100):
        if (ROOT / 'server-ready.json').exists(): break
        if server.poll() is not None: raise RuntimeError('fixture exited')
        time.sleep(.05)
    ready = json.loads((ROOT / 'server-ready.json').read_text())
    ownership = subprocess.check_output(['ss', '-H', '-ltnp', f'sport = :{ready["port"]}'], text=True).strip()
    assert f'pid={server.pid},' in ownership, ownership
    assert os.readlink(f'/proc/{server.pid}/cwd') == str(ROOT)
    print('Recorded port owner:', ownership, flush=True)
    for variant in ['fresh', 'existing']:
        for revision, worktree in [('before', '/home/ubuntu/wt/pr-23789-before'), ('after', '/home/ubuntu/wt/pr-23789')]:
            home = ROOT / f'{revision}-{variant}'
            if variant == 'existing':
                shutil.copytree(ROOT / 'before-fresh', home)
            else:
                (home / 'userdata').mkdir(parents=True)
            runtime = dict(version=1, pid=server.pid, port=ready['port'], host='127.0.0.1', origin=f'http://127.0.0.1:{ready["port"]}', startedAt='2026-10-22T00:00:00.000Z')
            (home / 'userdata/server-runtime.json').write_text(json.dumps(runtime) + '\n')
            (home / 'os-home').mkdir(exist_ok=True)
            env = dict(os.environ, HOME=str(home / 'os-home'), T3CODE_HOME=str(home), XDG_CONFIG_HOME=str(home / 'os-home/config'), XDG_CACHE_HOME=str(home / 'os-home/cache'), XDG_DATA_HOME=str(home / 'os-home/data'), NO_COLOR='1')
            for key in ['VITE_HTTP_URL', 'VITE_WS_URL', 'T3CODE_DEV_AUTH_TOKEN']:
                env.pop(key, None)
            initial = inventory(home)
            initial_db = db_summary(home)
            command = ['/home/ubuntu/.local/share/vite-plus/js_runtime/node/26.12.1/bin/node', f'{worktree}/apps/server/src/bin.ts', 'pair', '--base-dir', str(home)]
            completed = subprocess.run(command, cwd=worktree, env=env, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=120)
            output = re.sub(r'\x1b\[[0-9;]*m', '', completed.stdout + completed.stderr)
            token_issued = bool(re.search(r'^Token: \S+', output, re.M))
            # QR pixels encode the credential too: never save stdout from token issuance.
            if token_issued:
                safe = '\n'.join(line for line in output.splitlines() if line.startswith(('Pairing with ', 'Expires:', 'Note:')))
                safe += '\n[Pairing URL, token, and complete QR code REDACTED]'
            else:
                safe = output
            final = inventory(home)
            result = dict(revision=revision, variant=variant, command=command, exit=completed.returncode, token_issued=token_issued, transcript=safe, before=initial, after=final, new_files=sorted(final.keys()-initial.keys()), changed_files=sorted(p for p in initial.keys() & final.keys() if initial[p] != final[p]), db_before=initial_db, db_after=db_summary(home))
            results.append(result)
            print(revision, variant, completed.returncode, 'token:', token_issued, 'new:', result['new_files'], 'changed:', result['changed_files'], flush=True)
            if revision == 'before':
                assert completed.returncode == 0 and token_issued, safe
            else:
                assert completed.returncode == 1 and not token_issued, safe
                assert not result['new_files'] and not result['changed_files'], result
    (ROOT / 'results.json').write_text(json.dumps(dict(descriptor=DESCRIPTOR, port_owner=ownership, cwd=str(ROOT), results=results), indent=2))
finally:
    assert os.readlink(f'/proc/{server.pid}/cwd') == str(ROOT)
    server.terminate()
    server.wait(timeout=10)
    print('Stopped recorded fixture PID after verifying /proc cwd:', server.pid, flush=True)

```
