Consultant escalation policy + milestone delivery checks

Manager policy, active only when a company employs a consultant:
- a task that blows its wall-clock budget or blocks on machine failure
  (crashed worker, capability gap — anything except needs_input) is
  reassigned to the consultant with the failure context appended
- every objective rollup spawns a consultant review task: verify each
  deliverable against acceptance criteria, write milestone-check.md,
  verdict per deliverable, fix nothing

Also: employee_role_check widened to include consultant (db + live);
consultant sprite shirt color in the office.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
fez5587andClaude Fable 5 committed 2026-08-04 14:34:12 -05:00
1 parent 4796274ea5
commit 7ab6db469d
3 files changed
+56 -2

No files matched your search

+1 -1
View File
@@ -19,7 +19,7 @@ CREATE TABLE employee (
name text NOT NULL,
title text NOT NULL,
role text NOT NULL DEFAULT 'engineer'
CHECK (role IN ('manager','engineer','qa')),
CHECK (role IN ('manager','engineer','qa','consultant')),
department text NOT NULL DEFAULT '',
manager_id uuid REFERENCES employee(id),
hermes_profile text, -- Hermes profile name (ADR-001)
+54
View File
@@ -163,6 +163,25 @@ class Dispatcher:
event_type="milestone.update",
company_id=row["company_id"], work_item_id=row["id"],
payload={"objective_title": row["title"], "summary": update})
# milestone hit + consultant employed -> independent delivery check
consultant = await self._consultant_for(row["company_id"])
if consultant:
await conn.execute(
"INSERT INTO work_item (company_id, parent_id, type, title, "
"description, status, owner_id, acceptance_criteria) "
"VALUES (%s, %s, 'review', %s, %s, 'ready', %s, %s)",
(row["company_id"], row["id"],
f"Milestone delivery check: {row['title'][:60]}",
"The objective just completed. Independently verify delivery: "
"read the deliverable files in the workspace produced by its "
"tasks (their reports are appended below), check each against "
"the stated acceptance criteria, and write "
"milestone-check.md (overwrite if present) with a verdict per "
"deliverable — delivered / partial / missing — plus any "
"defects found. Do not fix anything yourself.",
consultant["id"],
db.Json(["milestone-check.md exists with a verdict per "
"deliverable and evidence for each verdict"])))
log.info("objective %s rolled up to done", row["id"])
async def _dispatch_ready(self) -> None:
@@ -284,10 +303,45 @@ class Dispatcher:
elif status == "blocked":
await self._block(item, kt.get("block_reason") or "hermes reported blocked",
event_type="task.blocked")
# machine failure (crashed worker, capability gap) -> consultant;
# needs_input stays blocked for the shareholder answer button
if kt.get("block_kind") != "needs_input":
await self._escalate(item, "local worker failed "
f"({kt.get('last_failure_error') or kt.get('block_kind') or 'blocked'})")
elif await self._over_budget(item):
await self._cap(item, kt)
await self._escalate(item, "wall-clock budget exceeded")
# todo/scheduled/ready/running: still waiting
async def _consultant_for(self, company_id) -> dict | None:
return await db.fetch_one(
"SELECT id, name FROM employee WHERE company_id = %s AND role = 'consultant' "
"ORDER BY created_at LIMIT 1", company_id)
async def _escalate(self, item: dict, reason: str) -> bool:
"""Manager policy: hand a failing task to the company consultant.
Only fires when a consultant is employed (hiring one = opting in to
external billing) and the failing owner isn't already the consultant."""
consultant = await self._consultant_for(item["company_id"])
if not consultant or consultant["id"] == item["owner_id"]:
return False
note = (f"\n\n[Escalated to consultant {consultant['name']}: {reason}. "
"A previous attempt by local staff did not deliver; produce the "
"deliverable yourself, completely.]")
async with db.pool.connection() as conn:
async with conn.transaction():
await conn.execute(
"UPDATE work_item SET owner_id=%s, status='ready', hermes_task_id=NULL, "
"description=description || %s, updated_at=now() WHERE id=%s",
(consultant["id"], note, item["id"]))
await conn.execute(
"UPDATE employee SET status='idle' WHERE id=%s", (item["employee_id"],))
await db.append_event(conn, actor="system", event_type="task.escalated",
company_id=item["company_id"], work_item_id=item["id"],
payload={"to": consultant["name"], "reason": reason})
log.info("escalated %s to consultant (%s)", item["id"], reason)
return True
async def _resume(self, item: dict) -> None:
async with db.pool.connection() as conn:
async with conn.transaction():
+1 -1
View File
@@ -63,7 +63,7 @@ const ROOMS = {
conf: { test:(x,y)=> x>18*T && y<8*T, W:[17*T+8, 4*T+8], D:[19*T+8, 4*T+8] },
lab: { test:(x,y)=> x>20*T && y>12*T, W:[24*T+8, 11*T+8], D:[24*T+8, 13*T+8] },
};
const ROLE_SHIRT = { manager:'#e0b354', engineer:'#5c9de0', qa:'#b48ce0' };
const ROLE_SHIRT = { manager:'#e0b354', engineer:'#5c9de0', qa:'#b48ce0', consultant:'#e6e2d8' };
const HAIR = ['#3a2a1c','#151412','#c9a24b','#8a3b22','#4a4e57'];
const px = (x,y,w,h,c) => { ctx.fillStyle=c; ctx.fillRect(x|0,y|0,w,h); };
const hash = s => [...s].reduce((a,ch)=>(a*31+ch.charCodeAt(0))>>>0, 7);