← back to Ticket System
Clear blockers when tickets complete
180ff40fbe6536adc50f8c2201c34186bcfe3202 · 2026-09-02 17:39:52 -0700 · Steve Abrams
Files touched
M lib.jsM lib.test.jsM test/mcp-server.test.js
Diff
commit 180ff40fbe6536adc50f8c2201c34186bcfe3202
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 2 17:39:52 2026 -0700
Clear blockers when tickets complete
---
lib.js | 8 +++++++-
lib.test.js | 9 +++++++++
test/mcp-server.test.js | 2 +-
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/lib.js b/lib.js
index 2febe64b..9f80763e 100644
--- a/lib.js
+++ b/lib.js
@@ -77,7 +77,13 @@ function tickets() {
if (ev.correlation_id) t.last_correlation_id = ev.correlation_id;
if (ev.type === 'comment') t.comments.push({ ts: ev.ts, agent: ev.agent || '', kind: ev.kind || 'comment', text: ev.text, correlation_id: ev.correlation_id || '' });
else if (ev.type === 'action') t.actions.push({ ts: ev.ts, agent: ev.agent || '', text: ev.text, correlation_id: ev.correlation_id || '' });
- else if (ev.type === 'status' && STATUSES.includes(ev.status)) { t.status = ev.status; t.status_since = ev.ts; }
+ else if (ev.type === 'status' && STATUSES.includes(ev.status)) {
+ t.status = ev.status;
+ t.status_since = ev.ts;
+ // A completed ticket cannot have an active current-state blocker. The
+ // blocker event remains in the append-only ledger for history.
+ if (ev.status === 'done') delete t.blocker;
+ }
else if (ev.type === 'assign') t.assignee = ev.agent || '';
else if (ev.type === 'blocker') t.blocker = cleanBlocker(ev.blocker);
else if (ev.type === 'designation' && KINDS.includes(ev.kind)) {
diff --git a/lib.test.js b/lib.test.js
index f4cf23c4..bb7ff817 100644
--- a/lib.test.js
+++ b/lib.test.js
@@ -98,6 +98,15 @@ test('structured blocker metadata folds and validates required fields', () => {
assert.throws(() => ticketBlocker(id, { type:'bad' }), /invalid blocker type/);
});
+test('done status clears the materialized blocker without rewriting history', () => {
+ const id = 'TK-10033-completed-blocker';
+ append({ ts: iso(), type: 'create', id, title: 'Completed blocker', agent: 'a' });
+ ticketBlocker(id, { type:'technical_dependency', condition:'proof pending', next_action:'run proof', owner:'a', evidence_at:iso() });
+ append({ ts: iso(), type: 'status', id, status: 'done', agent: 'a' });
+ assert.equal(tickets().get(id).blocker, undefined);
+ assert.ok(readEventLines().map(JSON.parse).some(ev => ev.type === 'blocker' && ev.id === id));
+});
+
// ── 3. comment vs action vs assign fold correctly; create body seeds a comment ─
test('comment, action, and assign events fold into the right places', () => {
const id = 'TK-10004-fold';
diff --git a/test/mcp-server.test.js b/test/mcp-server.test.js
index a34a12c2..c6e6b1e8 100644
--- a/test/mcp-server.test.js
+++ b/test/mcp-server.test.js
@@ -26,7 +26,7 @@ test('Codex ticket lifecycle persists to one canonical event ledger', () => {
call('ticket_blocker',{ticket:id,type:'technical_dependency',condition:'scope missing',next_action:'grant scope',owner:'steve',evidence_at:new Date().toISOString(),steve_one_action:true});
call('ticket_status',{ticket:id,status:'done'});
const got = call('ticket_get',{ticket:id});
- assert.equal(got.status,'done'); assert.equal(got.blocker.type,'technical_dependency'); assert.equal(got.actions.at(-1).text,'verified shared write'); assert.equal(got.actions.at(-1).correlation_id,logged.correlation_id);
+ assert.equal(got.status,'done'); assert.equal(got.blocker,undefined); assert.equal(got.actions.at(-1).text,'verified shared write'); assert.equal(got.actions.at(-1).correlation_id,logged.correlation_id);
const lines=fs.readFileSync(path.join(tmp,'events.jsonl'),'utf8').trim().split('\n').map(JSON.parse);
assert.ok(lines.every(e=>e.correlation_id));
});
← ecf0b99a record TK-10993 safe hold cycle
·
back to Ticket System
·
Enforce terminal ticket blocker precedence c351d5ce →