Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ for (const [zh, expectedLabel, expectedBoundary] of [
}
if (Object.values(unavailable.effects).some(Boolean)) throw new Error("authority-unavailable response must report zero effects");

// A configured request binding can be inspected before a source is selected.
// It must remain readable without inventing a Todo or claiming a launch.
for (const zh of [true, false]) {
const request: DelegationPreflight = {...unavailable, binding: {id: "request", agent_id: "receiver", todo_id: null},
state: "turn_blocked", request_required: true, authority_ready: true, authority_reason: null,
authority_state: "promoted", authority_next_action: "none"};
const html = renderToStaticMarkup(<DelegationPreflightStatus check={request} zh={zh}/>);
if (!html.includes(zh ? "等待原请求" : "Awaiting original request")) throw new Error("missing original request state");
if (/Todo|任务验收|启动条件已满足|prerequisites met/.test(html)) throw new Error("request inspection invented task readiness");
const missing: DelegationPreflight = {...request, request_required: false, state: "acceptance_unavailable",
acceptance_reason_code: "independent_delegation_validation_required",
acceptance_next_action: "review_original_request_validation"};
const refused = renderToStaticMarkup(<DelegationPreflightStatus check={missing} zh={zh}/>);
if (!refused.includes(zh ? "请求验收不可用" : "Request validation unavailable")) throw new Error("missing request validation state");
if (!refused.includes(zh ? "请求独立验收声明" : "independent request validation declaration")) throw new Error("wrong request repair owner");
if (/Todo|任务验收/.test(refused)) throw new Error("request repair requires an unrelated Todo");
}

for (const workspace_state of ["missing", "not_directory", "unavailable"] as const) {
const check: DelegationPreflight = {...unavailable, state: "workspace_unavailable",
workspace_state, workspace_next_action: "review_operator_workspace_binding",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ try {
if (body?.operation !== "read" || body.operation_id !== "accepted-analysis") return route.fallback();
api.loopxModeRequests.push({sessionId: configured.sessionId, ...body});
return checkUnavailable ? route.fulfill({status: 409, json: {error: "delegation output changed during validation"}})
: route.fulfill({json: {...legacyReadback, validation}});
: route.fulfill({json: {...legacyReadback,
...(validation.source === "request_validation" ? {todo_id: null} : {}), validation}});
};
await page.route("**/api/chat/sessions/*/loopx", checkedRead);
const recheck = evidence.getByRole("button", {name: "重新检查交付", exact: true});
Expand All @@ -90,6 +91,13 @@ try {
await checkObservation.getByText(outputVersions[1].sha256, {exact: true}).scrollIntoViewIfNeeded();
await page.screenshot({path: resolve(outputDir, "team-checked-output-mobile.png"), animations: "disabled"});
await page.setViewportSize({width: 1512, height: 980});
validation = {...currentValidation, source: "request_validation", pinned_file_count: 0};
await recheck.click();
await original().waitFor();
await evidence.getByText("本次验收依据", {exact: true}).click();
await checkObservation.getByText("请求独立验收规则", {exact: false}).waitFor();
assert.doesNotMatch(await checkObservation.innerText(), /任务验收规则|Task validation rules/,
"An independently validated original request must not claim a Todo validation basis");
// Another version's witness must never appear as a check of this report.
validation = {...validation, output_versions: [{ref: "report.json", sha256: "f".repeat(64)}, outputVersions[1]]};
await recheck.click();
Expand Down
12 changes: 6 additions & 6 deletions apps/presentation/dashboard/src/data/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1386,16 +1386,16 @@ export type LoopXModeSnapshot = {
settings: Partial<LoopXModeSettings> & { execution_config?: string };
native: { status: string; tokenBudget?: number; tokensUsed?: number };
registered_agents: string[]; paused: boolean; recovery_required: boolean;
members: Array<{id: string; agent_id: string; todo_id: string}>;
deliveries: Array<{operation_id: string; agent_id: string; todo_id: string; status: string}>;
members: Array<{id: string; agent_id: string; todo_id: string | null}>;
deliveries: Array<{operation_id: string; agent_id: string; todo_id: string | null; status: string}>;
ingress: Array<{client_ingress_id: string; mode: string; status: string}>;
turn_id?: string;
};
export function fetchLoopXMode(sessionId: string) {
return requestJson<LoopXModeSnapshot>(`/api/chat/sessions/${sessionId}/loopx`);
}
export type DelegationInventory = {
items: Array<{record_id: string; operation_id: string | null; agent_id?: string; todo_id?: string;
items: Array<{record_id: string; operation_id: string | null; agent_id?: string; todo_id?: string | null;
status: string; worker_active?: boolean; recovery_required: boolean | null;
artifacts?: Array<{ref: string; sha256: string}>; current_use?: DelegationReadback["current_use"]}>;
has_more: boolean; next_cursor: string | null; page_readback_complete: boolean;
Expand All @@ -1407,15 +1407,15 @@ export type DelegationDependency = {
};
export type DelegationAdoption = {
requester_agent_id: string; consumer_operation_id: string; consumer_request_id: string;
consumer_agent_id: string; consumer_todo_id: string; state: "current" | "unavailable";
consumer_agent_id: string; consumer_todo_id: string | null; state: "current" | "unavailable";
source_artifacts: Array<{ref: string; sha256: string}>;
consumer_artifacts: Array<{ref: string; sha256: string}>;
};
export type DelegationReadback = {
operation_id: string; request_id: string; agent_id: string; todo_id: string;
operation_id: string; request_id: string; agent_id: string; todo_id: string | null;
status: string; worker_active: boolean; recovery_required: boolean;
artifacts?: Array<{ref: string; sha256: string; text: string}>; error?: string;
validation?: {source: "goal_acceptance" | "todo_validation"; basis_sha256: string;
validation?: {source: "goal_acceptance" | "todo_validation" | "request_validation"; basis_sha256: string;
check_count: number; pinned_file_count: number; checked_at?: string;
output_versions?: Array<{ref: string; sha256: string}>; oracle_checks?: Array<OracleEvidence & {criterion_id: string}>};
task_failure?: {stage: "task_postcondition"; status: "failed" | "inconclusive" | "unavailable";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
export type DelegationPreflight = {
binding?: {id: string; agent_id: string; todo_id: string | null};
request_required?: boolean;
state: "workspace_unavailable" | "authority_unavailable" | "turn_blocked" | "acceptance_unavailable" | "runtime_unavailable" | "runtime_unverified" | "launchable";
workspace_state?: "missing" | "not_directory" | "unavailable";
workspace_next_action?: "review_operator_workspace_binding";
turn_eligible: boolean;
turn_lane?: {scope: "native_turn_lane"; state: string};
acceptance_ready: boolean;
acceptance_reason_code?: "independent_delegation_validation_required" | "completion_validation_declaration_unavailable" | "completion_validation_declaration_mismatch" | "validation_files_unavailable" | "acceptance_binding_unavailable" | null;
acceptance_next_action?: "review_original_todo_validation" | "restore_original_validation_files" | "review_original_task_acceptance" | "none";
acceptance_next_action?: "review_original_request_validation" | "review_original_todo_validation" | "restore_original_validation_files" | "review_original_task_acceptance" | "none";
turn_route: string | null;
authority_ready: boolean | null;
authority_reason: string | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const acceptanceDetails: Record<NonNullable<DelegationPreflight["acceptance_reas
};

const acceptanceActions: Record<Exclude<NonNullable<DelegationPreflight["acceptance_next_action"]>, "none">, {en: string; zh: string}> = {
review_original_request_validation: {
en: "Next: ask the original configuration owner to review the independent request validation declaration, then recheck",
zh: "下一步:请原配置责任人核对请求独立验收声明,再重新检查",
},
review_original_todo_validation: {
en: "Next: ask the original configuration owner to review the Todo validation declaration, then recheck",
zh: "下一步:请原配置责任人核对任务验收声明,再重新检查",
Expand All @@ -40,14 +44,24 @@ const acceptanceActions: Record<Exclude<NonNullable<DelegationPreflight["accepta
};

export function DelegationPreflightStatus({check, zh}: {check: DelegationPreflight; zh: boolean}) {
const request = check.binding?.todo_id === null;
const label = request && check.state === "turn_blocked" && check.request_required === true
? {en: "Awaiting original request", zh: "等待原请求"}
: request && check.state === "acceptance_unavailable"
? {en: "Request validation unavailable", zh: "请求验收不可用"}
: request && check.state === "turn_blocked"
? {en: "Request admission blocked", zh: "当前请求未获准执行"} : labels[check.state];
const lane = check.state === "turn_blocked" && check.turn_eligible === false
&& check.turn_lane?.scope === "native_turn_lane" ? check.turn_lane.state : null;
const busy = lane === "live";
const unknown = lane === "foreign_host" || lane === "unreadable";
const laneLabel = busy ? (zh ? "执行通道正在处理工作" : "Execution lane is busy")
: unknown ? (zh ? "执行通道状态无法确认" : "Execution lane state is unknown") : null;
const workspaceDetail = check.workspace_state ? workspaceDetails[check.workspace_state] : null;
const acceptanceDetail = check.state === "acceptance_unavailable" && check.acceptance_reason_code
const acceptanceDetail = request && check.state === "acceptance_unavailable"
&& check.acceptance_reason_code === "independent_delegation_validation_required"
? {en: "Independent request validation is required", zh: "原请求缺少独立验收声明"}
: check.state === "acceptance_unavailable" && check.acceptance_reason_code
&& Object.hasOwn(acceptanceDetails, check.acceptance_reason_code) ? acceptanceDetails[check.acceptance_reason_code] : null;
const acceptanceAction = check.state === "acceptance_unavailable" && check.acceptance_next_action
&& check.acceptance_next_action !== "none" && Object.hasOwn(acceptanceActions, check.acceptance_next_action)
Expand Down Expand Up @@ -82,7 +96,7 @@ export function DelegationPreflightStatus({check, zh}: {check: DelegationPreflig
? (zh ? "下一步:修复规范 Authority 读回" : "Next: repair canonical authority readback")
: acceptanceAction ? (zh ? acceptanceAction.zh : acceptanceAction.en) : null;
return <p role="status">
{laneLabel ?? (zh ? labels[check.state].zh : labels[check.state].en)}
{laneLabel ?? (zh ? label.zh : label.en)}
{detail ? ` · ${detail}` : ""}
{operationDetail ? ` · ${operationDetail}` : ""}
{nextAction ? ` · ${nextAction}` : ""}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export function GoalTeamEvidence({sessionId, operationId, zh, canMessage, ingres
<summary>{zh ? "本次验收依据" : "Current validation basis"}</summary>
{result.validation ? <>
<p>{result.validation.source === "goal_acceptance" ? (zh ? "Goal 验收规则" : "Goal acceptance rules")
: result.validation.source === "request_validation" ? (zh ? "请求独立验收规则" : "Independent request validation rules")
: (zh ? "任务验收规则" : "Task validation rules")}{" · "}
{result.validation.check_count} {zh ? "项检查" : "checks"}{" · "}
{result.validation.pinned_file_count} {zh ? "项文件版本固定" : "file pins"}</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {fetchLoopXTeamWork, inspectLoopXMember, delegationState, delegationState
import {GoalTeamEvidence} from "./goal-team-evidence";
import {DelegationPreflightStatus} from "./delegation-preflight-status";

type Member = {id: string; agent_id: string; todo_id: string};
type Member = {id: string; agent_id: string; todo_id: string | null};
type DelegationRecord = DelegationInventory["items"][number];
type PulseBucket = "executing" | "validating" | "accepted" | "attention" | "stopped" | "dispatched" | "unknown";
type CheckTone = "unchecked" | "ready" | "unverified" | "blocked";
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ How a settlement step binds to its receipt.
- Tier / 层级: `cross_runtime`; status / 状态: `canonical`.
- python: [`SettlementBindingKind`](../../loopx/control_plane/effect_program.py).
- typescript: [`SETTLEMENT_BINDING_KINDS`](../../loopx/control_plane/effect_program.ts).
- Values / 值: `todo`, `autonomous_replan`, `unbound`.
- Values / 值: `todo`, `autonomous_replan`, `request`, `unbound`.

## settlement_failure_kind

Expand Down
Loading
Loading