[object Object]

← back to Ticket System

Add GPT-6 Astra to ticket board Run Now

b1c662564dccabff3b69bc375c0927ee1421a786 · 2026-09-04 22:51:59 -0700 · Steve Abrams

Files touched

Diff

commit b1c662564dccabff3b69bc375c0927ee1421a786
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Sep 4 22:51:59 2026 -0700

    Add GPT-6 Astra to ticket board Run Now
---
 board.html                                 |   2 +-
 run-ticket.sh                              |   3 +-
 server.js                                  |   2 +-
 test/run-ticket-profiles.test.js           |   1 +
 verification/e2e-proof.json                | 116 ++++++++++++++++++++++++-----
 verification/tk-11284-3x.txt               |  15 ++++
 verification/tk-11284-browser.cjs          |  61 +++++++++++++++
 verification/tk-11284-gpt6-board.png       | Bin 0 -> 200121 bytes
 verification/tk-11284-launcher-dry-run.txt |   3 +
 9 files changed, 180 insertions(+), 23 deletions(-)

diff --git a/board.html b/board.html
index 535e9784..21d9e82a 100644
--- a/board.html
+++ b/board.html
@@ -131,7 +131,7 @@
   <span><span class="n" id="seln">0</span> selected</span>
   <select class="gsel" id="runProfile" title="Model used for Run Now">
     <optgroup label="Cloud · Claude"><option value="claude-opus">Claude Opus (4.8)</option><option value="claude-sonnet">Claude Sonnet</option><option value="claude-haiku">Claude Haiku</option><option value="claude-opus-5">Claude Opus 5</option><option value="claude-sonnet-5">Claude Sonnet 5</option><option value="claude-fable">Claude Fable 5.1</option></optgroup>
-    <optgroup label="Cloud · Codex / OpenAI"><option value="codex">Codex gpt-5.3 (default)</option><option value="codex-gpt52">Codex gpt-5.2</option></optgroup>
+    <optgroup label="Cloud · Codex / OpenAI"><option value="codex">Codex (configured default)</option><option value="codex-gpt6">GPT-6 (Astra)</option><option value="codex-gpt52">Codex gpt-5.2</option></optgroup>
     <optgroup label="Local · Ollama"><option value="local-qwen-27b">Local Qwen 27B Heretic</option><option value="local-qwen-14b">Local Qwen 14B</option></optgroup>
   </select>
   <button class="btn run" id="runBtn" title="Open a new iTerm2 window with the selected model, one per selected ticket">▶ Run Now</button>
diff --git a/run-ticket.sh b/run-ticket.sh
index 5337c3a3..6a401f04 100755
--- a/run-ticket.sh
+++ b/run-ticket.sh
@@ -5,7 +5,7 @@
 # authored ticket title ever reaches a shell). Steve, TK-10527 (2026-08-13):
 # "run ticket like the approvals opens a new iterm2 terminal with claude loaded first."
 #
-# Usage: run-ticket.sh <TK-id> [start-dir] [claude-sonnet|claude-opus|claude-haiku|claude-opus-5|claude-sonnet-5|claude-fable|codex|codex-gpt52|local-qwen-27b|local-qwen-14b]
+# Usage: run-ticket.sh <TK-id> [start-dir] [claude-sonnet|claude-opus|claude-haiku|claude-opus-5|claude-sonnet-5|claude-fable|codex|codex-gpt6|codex-gpt52|local-qwen-27b|local-qwen-14b]
 set -euo pipefail
 
 ID="${1:?usage: run-ticket.sh <TK-id> [start-dir]}"
@@ -31,6 +31,7 @@ case "$PROFILE" in
   claude-sonnet-5) RUNNER=(claude --model claude-sonnet-5); AGENT_PREFIX=claude-run ;;
   claude-fable)    RUNNER=(claude --model claude-fable-5-1); AGENT_PREFIX=claude-run ;;
   codex)         RUNNER=(/Users/macstudio3/.local/bin/codex); AGENT_PREFIX=codex-run ;;
+  codex-gpt6)    RUNNER=(/Users/macstudio3/.local/bin/codex --model gpt-6-astra); AGENT_PREFIX=codex-run ;;
   codex-gpt52)   RUNNER=(/Users/macstudio3/.local/bin/codex --model gpt-5.2); AGENT_PREFIX=codex-run ;;
   local-qwen-27b) RUNNER=(/Users/macstudio3/.local/bin/codex --oss --local-provider ollama --model qwen3.8-27b-heretic:latest); AGENT_PREFIX=local-qwen-27b-run ;;
   local-qwen-14b) RUNNER=(/Users/macstudio3/.local/bin/codex --oss --local-provider ollama --model qwen3:14b); AGENT_PREFIX=local-qwen-14b-run ;;
diff --git a/server.js b/server.js
index d4977776..b29f5bc2 100644
--- a/server.js
+++ b/server.js
@@ -12,7 +12,7 @@ const VERDICTS = path.join(DATA_DIR, 'dtd-verdicts.json');       // last batched
 const DTD_RUNNING = path.join(DATA_DIR, 'dtd-verdicts.running'); // present while a sweep is in flight
 const RUN_SH = path.join(__dirname, 'run-ticket.sh');           // opens an iTerm2 Claude session
 const DTD_RUN = path.join(__dirname, 'dtd-run.js');             // batched panel.sh sweep
-const RUN_PROFILES = new Set(['claude-sonnet', 'claude-opus', 'claude-haiku', 'claude-opus-5', 'claude-sonnet-5', 'claude-fable', 'codex', 'codex-gpt52', 'local-qwen-27b', 'local-qwen-14b']);
+const RUN_PROFILES = new Set(['claude-sonnet', 'claude-opus', 'claude-haiku', 'claude-opus-5', 'claude-sonnet-5', 'claude-fable', 'codex', 'codex-gpt6', 'codex-gpt52', 'local-qwen-27b', 'local-qwen-14b']);
 const DEFAULT_RUN_PROFILE = 'codex';
 const RUN_PROFILE_OVERRIDE = '/tmp/ticket-run-profile-override.json';
 
diff --git a/test/run-ticket-profiles.test.js b/test/run-ticket-profiles.test.js
index 63e84809..16597ce4 100644
--- a/test/run-ticket-profiles.test.js
+++ b/test/run-ticket-profiles.test.js
@@ -12,6 +12,7 @@ test('allowlisted launcher profiles map to fixed commands', () => {
   assert.match(run('claude-opus'), /profile=claude-opus[\s\S]*claude --model opus/);
   assert.match(run('claude-haiku'), /profile=claude-haiku[\s\S]*claude --model haiku/);
   assert.match(run('codex'), /profile=codex[\s\S]*\/Users\/macstudio3\/\.local\/bin\/codex/);
+  assert.match(run('codex-gpt6'), /profile=codex-gpt6[\s\S]*agent=codex-run-11027[\s\S]*\/Users\/macstudio3\/\.local\/bin\/codex --model gpt-6-astra/);
   assert.match(run('local-qwen-27b'), /profile=local-qwen-27b[\s\S]*--oss --local-provider ollama --model qwen3\.8-27b-heretic:latest/);
   assert.match(run('local-qwen-14b'), /profile=local-qwen-14b[\s\S]*--oss --local-provider ollama --model qwen3:14b/);
 });
diff --git a/verification/e2e-proof.json b/verification/e2e-proof.json
index 05a187a2..a64a3e87 100644
--- a/verification/e2e-proof.json
+++ b/verification/e2e-proof.json
@@ -1,24 +1,100 @@
 {
-  "intent": "Select tickets and run them through either approved cloud profiles or installed task-capable local Ollama profiles.",
+  "ticket": "TK-11284-add-gpt-6-to-ticket-board-model-selector",
+  "checked_at": "2026-09-05T05:50:55.821Z",
+  "checks": [
+    {
+      "name": "GPT-6 selector persists across reload",
+      "verdict": "PASS",
+      "detail": "Selected codex-gpt6; localStorage and rendered selection agree after reload."
+    },
+    {
+      "name": "Real Run Now UI sends GPT-6 profile to live API",
+      "verdict": "PASS",
+      "detail": {
+        "launched": [],
+        "skipped": [
+          {
+            "id": "TK-11284-add-gpt-6-to-ticket-board-model-selector",
+            "why": "already-doing"
+          }
+        ],
+        "profile": "codex-gpt6"
+      }
+    },
+    {
+      "name": "Existing doing ticket prevents duplicate launch",
+      "verdict": "PASS",
+      "detail": "No worker or paid model call launched by browser verification."
+    },
+    {
+      "name": "Unknown profile rejected",
+      "verdict": "PASS",
+      "detail": {
+        "status": 400,
+        "body": {
+          "error": "invalid run profile"
+        }
+      }
+    },
+    {
+      "name": "Remote execution guard preserved",
+      "verdict": "PASS",
+      "detail": {
+        "status": 403
+      }
+    },
+    {
+      "name": "Unauthenticated execution rejected",
+      "verdict": "PASS",
+      "detail": {
+        "status": 401
+      }
+    },
+    {
+      "name": "Actual launcher builds explicit GPT-6 command and gated ticket prompt",
+      "verdict": "PASS",
+      "detail": "codex --model gpt-6-astra; agent codex-run-11284; dry-run output retained."
+    },
+    {
+      "name": "Browser has zero page errors",
+      "verdict": "PASS",
+      "detail": []
+    }
+  ],
+  "intent": "Add selectable GPT-6 (Astra) to the ticket board and generate an explicit gpt-6-astra launch command.",
   "risk_tier": "R2",
-  "environment": "Mac2 live PM2 ticket-board on 127.0.0.1:9794",
-  "build_identity": "c6f392c",
-  "timestamp": "2026-08-31T18:00:00Z",
-  "baseline": "Run Now supported four cloud profiles but no local models.",
-  "assertions": [
-    {"boundary":"unit", "result":"PASS", "evidence":"27/27 tests; all six profiles map to fixed commands; unknown profiles rejected before AppleScript"},
-    {"boundary":"runtime", "result":"PASS", "evidence":"Ollama API confirms qwen3.8-27b-heretic:latest and qwen3:14b are installed"},
-    {"boundary":"ui", "result":"PASS", "evidence":"Checkbox selection reveals six choices grouped as Cloud and Local · Ollama, including Local Qwen 27B Heretic and Local Qwen 14B"},
-    {"boundary":"ui-persistence", "result":"PASS", "evidence":"Selected local-qwen-27b profile persisted through reload using localStorage"},
-    {"boundary":"browser-js", "result":"PASS", "evidence":"Playwright selection flow completed with zero page errors"},
-    {"boundary":"3x", "result":"PASS", "evidence":"HTTP, headless render, Playwright interaction, and Chrome parity passed; 4/4 attempted, Safari/Firefox skipped because engines unavailable under --no-open"},
-    {"boundary":"api-happy", "result":"PASS", "evidence":"POST /api/run accepted local-qwen-27b and local-qwen-14b and preserved stopped-ticket skip"},
-    {"boundary":"api-negative", "result":"PASS", "evidence":"Unapproved local-qwen2.5vl profile returned HTTP 400 invalid run profile"},
-    {"boundary":"service", "result":"PASS", "evidence":"ticket-board online after restart; unstable restarts 0"},
-    {"boundary":"side-effects", "result":"PASS", "evidence":"No model session launched during proof; stopped test ticket and dry-run launcher exercised boundaries without ticket work"}
+  "environment": "Running ticket-board on 127.0.0.1:9794",
+  "baseline": "No explicit GPT-6 profile; default Codex label incorrectly claimed GPT-5.3.",
+  "build_identity": {
+    "board.html": "9867e19cb4900a04a5f97a493b053034019c7de6461567915014c53f365d39bb",
+    "server.js": "eaff74765854acbbf59a3790e1529c9a91ba2109575367c7dca84efdd486f524",
+    "run-ticket.sh": "bb4b8f57d7a638f6edc10eaef1754971370ae1ff7c6d25a4fcd34da8ce511170",
+    "test/run-ticket-profiles.test.js": "013a9905606839cb3b3f29736c0bdbf682d35cbdf92874f44945790228e191be"
+  },
+  "commands": [
+    "node --check server.js",
+    "bash -n run-ticket.sh",
+    "npm test: 29/29 PASS",
+    "git diff --check",
+    "serialized PM2 restart ticket-board",
+    "node /tmp/tk11284-browser.cjs",
+    "3x/run.js --selector table --no-open"
   ],
-  "artifacts": ["/var/folders/rq/j8g1f7nn6jv6_lr1cfmqym6w0000gn/T/3x-bOzrjB/render.png"],
-  "rollback": "git revert c6f392c and restart ticket-board",
-  "cleanup": "No test session or external side effect created.",
-  "verdict": "PASS"
+  "browser_smoke": {
+    "attempted": 4,
+    "passed": 4,
+    "skipped": [
+      "Safari engine unavailable",
+      "Firefox engine unavailable"
+    ]
+  },
+  "cleanup": "Fresh isolated browser context closed; no extra worker, model request, ticket status change or other product mutation during verification.",
+  "limits": "New iTerm window/model inference was not launched: existing launch path checked through actual shell dry-run, and live Run Now used an already-doing ticket. Cross-engine optional checks unavailable.",
+  "verdict": "PASS",
+  "artifacts": [
+    "verification/tk-11284-gpt6-board.png",
+    "verification/tk-11284-browser.cjs",
+    "verification/tk-11284-3x.txt",
+    "verification/tk-11284-launcher-dry-run.txt"
+  ]
 }
diff --git a/verification/tk-11284-3x.txt b/verification/tk-11284-3x.txt
new file mode 100644
index 00000000..6725eea2
--- /dev/null
+++ b/verification/tk-11284-3x.txt
@@ -0,0 +1,15 @@
+
+/3x — verifying http://127.0.0.1:9794/ (auth admin:•••)
+
+Phase A — 3 unique methods:
+  [PASS] M1 HTTP contract  request layer — HTTP 200 text/html
+  [PASS] M2 headless render  render layer — screenshot 249KB → /var/folders/rq/j8g1f7nn6jv6_lr1cfmqym6w0000gn/T/3x-8yvpsr/render.png
+  [PASS] M3 automation E2E  interaction layer — 1×"table", 0 JS errors
+
+Phase B — 3 browsers (cross-browser):
+  [PASS] B4 Google Chrome  cross-browser — automated render OK
+  [SKIP] B5 Safari  cross-browser — engine not installed, --no-open set
+  [SKIP] B6 Firefox  cross-browser — engine not installed, --no-open set
+
+  RESULT → 4/4 passed, 2 skipped
+  artifacts: /var/folders/rq/j8g1f7nn6jv6_lr1cfmqym6w0000gn/T/3x-8yvpsr
diff --git a/verification/tk-11284-browser.cjs b/verification/tk-11284-browser.cjs
new file mode 100644
index 00000000..8206a09a
--- /dev/null
+++ b/verification/tk-11284-browser.cjs
@@ -0,0 +1,61 @@
+const { chromium } = require('/Users/macstudio3/Projects/Designer-Wallcoverings/node_modules/playwright');
+const assert = require('node:assert/strict');
+const fs = require('node:fs');
+const { execFileSync } = require('node:child_process');
+const root = '/Users/macstudio3/Projects/ticket-system';
+const ticket = 'TK-11284-add-gpt-6-to-ticket-board-model-selector';
+const evidence = { ticket, checked_at: new Date().toISOString(), checks: [] };
+const check = (name, detail) => evidence.checks.push({ name, verdict: 'PASS', detail });
+(async () => {
+  const browser = await chromium.launch({ executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', headless: true });
+  try {
+    const context = await browser.newContext({ httpCredentials: { username: 'admin', password: 'DW2024!' }, viewport: { width: 1440, height: 1000 } });
+    const page = await context.newPage();
+    const errors = [];
+    page.on('pageerror', e => errors.push(e.message));
+    await page.goto('http://127.0.0.1:9794/?section=doing&layout=kv');
+    await page.waitForSelector('#runProfile', { state: 'attached' });
+    const row = page.locator('tr').filter({ has: page.locator('a[title="' + ticket + '"]') });
+    await row.locator('.rowcb').check();
+    assert.equal(await page.locator('#runProfile option[value="codex-gpt6"]').textContent(), 'GPT-6 (Astra)');
+    await page.selectOption('#runProfile', 'codex-gpt6');
+    assert.equal(await page.evaluate(() => JSON.parse(localStorage.getItem('tkRunProfile'))), 'codex-gpt6');
+    await page.reload();
+    assert.equal(await page.locator('#runProfile').inputValue(), 'codex-gpt6');
+    check('GPT-6 selector persists across reload', 'Selected codex-gpt6; localStorage and rendered selection agree after reload.');
+    await row.locator('.rowcb').check();
+    await page.screenshot({ path: '/tmp/tk11284-gpt6-board.png' });
+    const requestPromise = page.waitForRequest(r => r.url().endsWith('/api/run') && r.method() === 'POST');
+    const responsePromise = page.waitForResponse(r => r.url().endsWith('/api/run') && r.request().method() === 'POST');
+    await page.locator('#runBtn').click();
+    const request = await requestPromise;
+    assert.deepEqual(request.postDataJSON(), { ids: [ticket], profile: 'codex-gpt6' });
+    const response = await responsePromise;
+    assert.equal(response.status(), 200);
+    const result = await response.json();
+    assert.equal(result.profile, 'codex-gpt6');
+    assert.deepEqual(result.launched, []);
+    assert.deepEqual(result.skipped, [{ id: ticket, why: 'already-doing' }]);
+    check('Real Run Now UI sends GPT-6 profile to live API', result);
+    check('Existing doing ticket prevents duplicate launch', 'No worker or paid model call launched by browser verification.');
+    const invalid = await context.request.post('http://127.0.0.1:9794/api/run', { data: { ids: [], profile: 'codex-gpt6;invalid' } });
+    assert.equal(invalid.status(), 400);
+    check('Unknown profile rejected', { status: invalid.status(), body: await invalid.json() });
+    const proxied = await context.request.post('http://127.0.0.1:9794/api/run', { headers: { 'x-forwarded-for': '198.51.100.1' }, data: { ids: [], profile: 'codex-gpt6' } });
+    assert.equal(proxied.status(), 403);
+    check('Remote execution guard preserved', { status: proxied.status() });
+    const unauthorized = await fetch('http://127.0.0.1:9794/api/run', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ids: [], profile: 'codex-gpt6' }) });
+    assert.equal(unauthorized.status, 401);
+    check('Unauthenticated execution rejected', { status: unauthorized.status });
+    const payload = execFileSync('bash', [root + '/run-ticket.sh', ticket, root, 'codex-gpt6'], { encoding: 'utf8', env: { ...process.env, RUN_TICKET_DRY_RUN: '1' } });
+    assert.match(payload, /codex --model gpt-6-astra/);
+    assert.match(payload, /agent=codex-run-11284/);
+    assert.match(payload, /pending-approval/);
+    fs.writeFileSync('/tmp/tk11284-launcher-dry-run.txt', payload);
+    check('Actual launcher builds explicit GPT-6 command and gated ticket prompt', 'codex --model gpt-6-astra; agent codex-run-11284; dry-run output retained.');
+    assert.deepEqual(errors, []);
+    check('Browser has zero page errors', errors);
+  } finally { await browser.close(); }
+  fs.writeFileSync('/tmp/tk11284-browser-evidence.json', JSON.stringify(evidence, null, 2) + '\n');
+  console.log(JSON.stringify(evidence, null, 2));
+})().catch(e => { console.error(e); process.exitCode = 1; });
diff --git a/verification/tk-11284-gpt6-board.png b/verification/tk-11284-gpt6-board.png
new file mode 100644
index 00000000..272e5ca0
Binary files /dev/null and b/verification/tk-11284-gpt6-board.png differ
diff --git a/verification/tk-11284-launcher-dry-run.txt b/verification/tk-11284-launcher-dry-run.txt
new file mode 100644
index 00000000..f3c5ce94
--- /dev/null
+++ b/verification/tk-11284-launcher-dry-run.txt
@@ -0,0 +1,3 @@
+profile=codex-gpt6
+agent=codex-run-11284
+payload=cd /Users/macstudio3/Projects/ticket-system && ( for i in 1 2 3 4; do sleep 5; "/Users/macstudio3/bin/tk-iterm-title" TK-11284; done ) >/dev/null 2>&1 & /Users/macstudio3/.local/bin/codex --model gpt-6-astra export\ TK_AGENT=codex-run-11284.\ You\ are\ driving\ ticket\ TK-11284-add-gpt-6-to-ticket-board-model-selector\ to\ completion.\ First\ run:\ tk\ inbox\ \(act\ on\ any\ DMs\)\,\ then\ tk\ show\ TK-11284-add-gpt-6-to-ticket-board-model-selector\ for\ full\ context.\ You\ now\ OWN\ this\ ticket:\ tk\ take\ TK-11284-add-gpt-6-to-ticket-board-model-selector.\ Work\ it\ to\ done\ per\ AGENTS.md/CLAUDE.md\'s\ operating\ loop\ —\ tk\ log\ EVERY\ action\,\ tk\ comment\ reasoning\,\ dm\ peers\ with\ tk\ dm\ if\ you\ need\ help.\ Any\ customer-facing\ /\ destructive\ /\ spend\ /\ DNS\ /\ publish\ /\ send-to-list\ /\ remote-push\ /\ canonical\ dw_unified\ or\ Shopify\ write\ is\ GATED:\ draft\ it\ to\ ~/.claude/yolo-queue/pending-approval/\ and\ STOP\ —\ never\ auto-fire.\ When\ the\ work\ is\ genuinely\ complete\ AND\ verified:\ tk\ done\ TK-11284-add-gpt-6-to-ticket-board-model-selector.

← 23bc2208 snapshot before adding GPT-6 ticket profile  ·  back to Ticket System  ·  Record bounded ticket monitoring cycle and verified zero-cos 91efa3aa →