import { finalEntries } from "../../materials/index.ts"; import { assignEntries as assign } from "../../rules/index.ts"; import type { Json } from "../../vocab/index.ts"; import { runModelTask } from "../model-task.ts"; import type { Next } from "../next-step.ts"; import { halt, USER_STOPPED, type Study, type StudyEnding } from "../study.ts"; // 第零轮(方法.md 4.2):三个研究者阶段派任务,认领之后由程序分配入口。 /** * 派一个研究者阶段里要派的人,同时跑,各自一个会话(任务书 12 第 2.6 节)。第零轮的提交种类交上来之后没有要另算的东西。 * 有人没交上(没交或出错),等这次派发的会话全部结束后停下,不打断别人(第 2.4 节)。 * 某个会话抛出内部错误时,也等别人结束再把它抛出去。 */ export async function dispatchStage(s: Study, next: Extract): Promise { const settled = await Promise.allSettled( next.actors.map((actor) => runModelTask(s, { kind: next.kind, actor, stageId: next.stageId, object: null, known: () => null })), ); const failure = settled.find((r) => r.status === "rejected"); if (failure !== undefined) throw failure.reason; if (s.stop.aborted) return USER_STOPPED; const results = settled.map((r) => (r as PromiseFulfilledResult>>).value); const missed = results.flatMap(({ call, ending }) => ending.status === "notSubmitted" || ending.status === "failed" ? [{ call, text: `${ending.status === "failed" ? "出错" : "没交"}:${ending.reason}` }] : [], ); if (missed.length === 0) return null; return halt(s.ledger, `阶段 ${next.stageId} 有人没交上,等这次派发的会话全部结束后停下:${missed.map((m) => `调用 ${m.call},${m.text}`).join(";")}`, missed.map((m) => m.call)); } /** * 分配(方法.md 4.2"分配规则"):每人最后一份认领和最终有效的入口交给 rules 的 assignEntries,写一条入口分配决定。 * assignEntries 不在规则登记表里,规则名就写它,版本 1;没有方法参数,也不用随机。 */ export function assignEntries(s: Study): void { const roster = s.ledger.records().find((r) => r.kind === "stageOpen" && r.content.stage === "claim" && r.content.round === 0); const claim = roster!.content as { stageId: string; roster: string[] }; const researchers = claim.roster.map((id) => { const last = s.ledger.latestSubmission({ stageId: claim.stageId, author: id, kind: "claim", target: null, item: null }); return { id, choices: (last!.content.content as { choices: string[] }).choices }; }); const entries = finalEntries(s.ledger).map((e) => ({ id: e.id, author: e.author })); const input = { researchers, entries }; s.ledger.append("decision", { decision: "entries", round: 0, rule: "assignEntries", ruleVersion: 1, params: null, seed: null, input, output: assign(input) as unknown as Json }); }