From 1b6b27357c817359574605b854f6468917da314d Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Mon, 16 Mar 2026 21:30:36 +0000 Subject: fix: hide deployment badge when not deployed and trim notification button label - Deployment badge now returns null (hidden) when includes_fix is false instead of showing "Not deployed" noise - Badge also suppressed when fix_commits is empty (no tracked commits to check) - Notification button label trimmed to just the bell emoji - Preamble: warn agents not to use absolute paths in git commands (sandbox bypass) Co-Authored-By: Claude Sonnet 4.6 --- internal/executor/preamble.go | 1 + internal/executor/preamble_test.go | 7 +++++++ web/app.js | 10 +++++----- web/index.html | 2 +- web/test/deployment-badge.test.mjs | 24 +++++++++--------------- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/internal/executor/preamble.go b/internal/executor/preamble.go index f5dba2b..b949986 100644 --- a/internal/executor/preamble.go +++ b/internal/executor/preamble.go @@ -45,6 +45,7 @@ The sandbox is rejected if there are any uncommitted modifications. - One commit is fine. Multiple focused commits are also fine. - If you realise the task was already done and you made no changes, that is also fine — just exit cleanly without committing. - Do not exit with uncommitted edits. +- **CRITICAL:** Run ALL git commands from your current directory — do NOT use absolute paths or "cd && git ...". Your working directory IS the project. Using absolute paths bypasses the sandbox and breaks commit tracking. --- diff --git a/internal/executor/preamble_test.go b/internal/executor/preamble_test.go index 984f786..5c31b4f 100644 --- a/internal/executor/preamble_test.go +++ b/internal/executor/preamble_test.go @@ -22,3 +22,10 @@ func TestPlanningPreamble_SummaryInstructsEchoToFile(t *testing.T) { t.Error("planningPreamble should show example of writing to $CLAUDOMATOR_SUMMARY_FILE via echo") } } + +func TestPlanningPreamble_GitDiscipline_ForbidsAbsolutePaths(t *testing.T) { + // Agents must not bypass the sandbox by using absolute project paths in git commands. + if !strings.Contains(planningPreamble, "do NOT use absolute paths") { + t.Error("planningPreamble should warn agents not to use absolute paths in git commands") + } +} diff --git a/web/app.js b/web/app.js index 73f5a5c..dca4472 100644 --- a/web/app.js +++ b/web/app.js @@ -107,8 +107,7 @@ export function renderDeploymentBadge(status, doc = (typeof document !== 'undefi span.className = 'deployment-badge deployment-badge--deployed'; span.textContent = '✓ Deployed'; } else { - span.className = 'deployment-badge deployment-badge--pending'; - span.textContent = '⚠ Not deployed'; + return null; } if (status.deployed_commit) { span.title = `Deployed commit: ${status.deployed_commit.slice(0, 8)}`; @@ -179,8 +178,9 @@ function createTaskCard(task) { if (csBadge) card.appendChild(csBadge); } - // Deployment status badge for READY tasks - if (task.state === 'READY' && task.deployment_status != null) { + // Deployment status badge for READY tasks — only when there are tracked commits to check. + if (task.state === 'READY' && task.deployment_status != null && + task.deployment_status.fix_commits && task.deployment_status.fix_commits.length > 0) { const depBadge = renderDeploymentBadge(task.deployment_status); if (depBadge) card.appendChild(depBadge); } @@ -2660,7 +2660,7 @@ async function enableNotifications(btn) { if (!res.ok) throw new Error(`Subscribe failed: HTTP ${res.status}`); if (btn) { - btn.textContent = '🔔 On'; + btn.textContent = '🔔'; btn.disabled = true; } } catch (err) { diff --git a/web/index.html b/web/index.html index 64dd486..c17601b 100644 --- a/web/index.html +++ b/web/index.html @@ -17,7 +17,7 @@ - + diff --git a/web/test/deployment-badge.test.mjs b/web/test/deployment-badge.test.mjs index afb4a59..438fb27 100644 --- a/web/test/deployment-badge.test.mjs +++ b/web/test/deployment-badge.test.mjs @@ -33,8 +33,14 @@ describe('renderDeploymentBadge', () => { assert.equal(el, null); }); - it('returns element with deployment-badge class for valid status', () => { - const status = { deployed_commit: 'abc123', fix_commits: [], includes_fix: false }; + it('returns null when includes_fix is false', () => { + const status = { deployed_commit: 'abc123', fix_commits: [{ hash: 'aabbcc', message: 'fix' }], includes_fix: false }; + const el = renderDeploymentBadge(status, makeDoc()); + assert.equal(el, null); + }); + + it('returns element with deployment-badge class when includes_fix is true', () => { + const status = { deployed_commit: 'abc123', fix_commits: [{ hash: 'aabbcc', message: 'fix' }], includes_fix: true }; const el = renderDeploymentBadge(status, makeDoc()); assert.ok(el, 'element should not be null'); assert.ok(el.className.includes('deployment-badge'), `className should include deployment-badge, got: ${el.className}`); @@ -46,26 +52,14 @@ describe('renderDeploymentBadge', () => { assert.ok(el.textContent.includes('Deployed'), `expected "Deployed" in "${el.textContent}"`); }); - it('shows "Not deployed" text when includes_fix is false', () => { - const status = { deployed_commit: 'abc123', fix_commits: [{ hash: 'aabbcc', message: 'fix' }], includes_fix: false }; - const el = renderDeploymentBadge(status, makeDoc()); - assert.ok(el.textContent.includes('Not deployed'), `expected "Not deployed" in "${el.textContent}"`); - }); - it('applies deployed class when includes_fix is true', () => { const status = { deployed_commit: 'abc123', fix_commits: [{ hash: 'aabbcc', message: 'fix' }], includes_fix: true }; const el = renderDeploymentBadge(status, makeDoc()); assert.ok(el.className.includes('deployment-badge--deployed'), `className: ${el.className}`); }); - it('applies pending class when includes_fix is false', () => { - const status = { deployed_commit: 'abc123', fix_commits: [{ hash: 'aabbcc', message: 'fix' }], includes_fix: false }; - const el = renderDeploymentBadge(status, makeDoc()); - assert.ok(el.className.includes('deployment-badge--pending'), `className: ${el.className}`); - }); - it('returns null for doc=null', () => { - const status = { deployed_commit: 'abc', fix_commits: [], includes_fix: false }; + const status = { deployed_commit: 'abc', fix_commits: [], includes_fix: true }; const el = renderDeploymentBadge(status, null); assert.equal(el, null); }); -- cgit v1.2.3