← 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
M board.htmlM run-ticket.shM server.jsM test/run-ticket-profiles.test.jsM verification/e2e-proof.jsonA verification/tk-11284-3x.txtA verification/tk-11284-browser.cjsA verification/tk-11284-gpt6-board.pngA verification/tk-11284-launcher-dry-run.txt
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 →