tasks, bus, harness, seat: the approved requirement ids as data (#1584)

Row 90, round 2. Dewey built it, Filbert approved it (comment 28068) on
manifest 95611274 (21 paths, base b8539480). The approved PRD's
requirement ids live in packages/tasks/requirements.json. task_create
refuses an id outside it, and the PM session gets a list_requirements
tool. Round 2 adds requirements.mjs to the sandbox's RUNNER_FILES
(decision 127). Sage gate on c047d028 plus the patch, 23:50:16Z to
23:54:26Z: tasks 89, bus 111, harness 66, webui 101, cli 123, seat 33,
business 60, control-board 124, queue 150, conversation 182, discord 178,
ledger 78, runs 43, mosaic 69, all fail 0. Every scripts/test-*.sh
exited 0.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-12 18:55:49 -05:00
co-authored by Claude Opus 5.5
parent e4ce090716
commit e918a915a8
21 changed files with 382 additions and 26 deletions
+2
View File
@@ -69,6 +69,8 @@ function prompt({ contract, resolved, session, tools, untyped }) {
`- Bus tools: ${tools.map((t) => t.name).join(", ")}. The broker decides every call; a refusal names its reason.`,
"- Each message to you arrives as one turn. Your final answer goes back to the sender as the reply, so end each turn with the answer itself.",
"- You never hold a token. You act on the tracker, the forge and other roles only through the bus tools.",
// Row 90 (#1584): PM fault 10 (#228 c91).
"- Only the human stops a run, with `mosaic stop`. If you think a run should stop, raise a role.revoke decision with blocking false and the role instance as target, naming the run and saying why.",
];
if (untyped.length) lines.push(`- Actions you hold that have no bus tool yet: ${untyped.join(", ")}. Say so instead of working around it.`);
return lines.join("\n") + "\n";
+2
View File
@@ -63,6 +63,8 @@ export function turnRequest(m) {
const head = [`Message ${m.id} from ${m.from_role}`, `class ${m.class}`];
if (m.in_reply_to) head.push(`in reply to ${m.in_reply_to}`);
if (m.decision) head.push(`citing decision ${m.decision}`);
// Row 90 (#1584): the human input id task_create cites as its request.
if (m.request) head.push(`request ${m.request}`);
return `${head.join(", ")}:\n\n${m.body}`;
}
+6 -3
View File
@@ -44,8 +44,8 @@ const TASK_TOOLS = {
priority: PRIORITY,
labels: LABEL_IDS,
relations: { type: "array", items: RELATION, maxItems: 50 },
request: str("Id of the message or human input this task answers"),
requirement: str("Requirement id, such as REQ-CRED-2", { pattern: "^REQ-[A-Z]+-[1-9][0-9]*$" }),
request: str("The request id of the human message this task answers, shown as \"request <id>\" in that message's header; not the message's own id"),
requirement: str("Requirement id from list_requirements, such as REQ-CRED-2", { pattern: "^REQ-[A-Z]+-[1-9][0-9]*$" }),
decision: COMMON.decision,
}, ["title", "request", "requirement"]],
"task.assign": ["task_assign", "Assign an unassigned task to a role.", { ...COMMON, role: str("Role instance to assign") }, ["task_ref", "role"]],
@@ -103,7 +103,7 @@ export function typedTools({ resolved, arbiter = false, tracker = false }) {
question: str("The question, with enough context to answer it"),
options: { type: "array", minItems: 2, maxItems: 9, items: obj({ key: str("Short key"), text: str("What this option means") }, ["key", "text"]) },
recommendation: str("Your recommended option key, with a reason"),
blocking: { type: "boolean", description: "True when you can't continue without the answer" },
blocking: { type: "boolean", description: "True only for a decision that holds a task: it needs task_ref, and the task waits for the answer. A request with no task is false" },
target: str("What the action applies to, such as a role instance or task reference"),
approvalChoice: str("The option key that approves the action"),
task_ref: TASK_REF,
@@ -129,6 +129,9 @@ export function typedTools({ resolved, arbiter = false, tracker = false }) {
after: str("The next value of the previous page"),
}));
add("get_task", "tasks", null, "Read one tracker task in full, description included.", obj({ task_ref: TASK_REF }, ["task_ref"]));
// Row 90 (#1584): the ids task_create takes, for the sessions that hold it.
if (held.has("task.create"))
add("list_requirements", "requirements", null, "List the approved PRD's requirement ids, each with a one-line title. task_create takes only these. When none fits a request, raise a prd.approve decision instead of creating the task.", obj({}));
}
return tools;
}