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
Original file line number Diff line number Diff line change
Expand Up @@ -1641,7 +1641,7 @@ codec retire when CLI/Host callers use the typed kernel directly. The target is
TypeScript ownership throughout, with no Python rule fallback.
The adapter transports bounded facts and diagnostic strings, then applies the
typed quota patch without round-tripping source numbers or metadata. Receipt-bound
overlays, later route/action builders and effect authority retain their owners.
overlays, remaining route/action builders and effect authority retain their owners.
The existing effective-action vocabulary and generated TS binding are reused;
its canonical Python enum remains until a separate contract-owner cutover.
The TypeScript producer witness executes the real typed classifier against shared guard fixtures and rejects a
Expand All @@ -1650,6 +1650,15 @@ semantic parity for one base-admission consumer. Full-CLI performance acceptance
is held for owner review after a p95 regression; whole-Goal migration and
provider/default qualification remain open.

The task-scoped `goal_route_hint` override now comes back in that same
`quota.run_decision` response. Python projects the lane count from the existing
task-orchestration source fact. TypeScript owns the ready-state check, route
decision and coordination wording. Python's duplicate `task_goal_route_hint` decision is
deleted, leaving only the bounded merge into the assembled hint. This adds no
request, provider read or authority. Other Goal-route and primary-action
builders remain separate migration work; this does not complete the quota read
transaction or claim a performance gain.

**Long-history transport boundary.** Replan history still has one TS decision
owner. Small requests retain the inline codec; larger complete fact snapshots
travel through a private, digest-bound local file reference. The same reducer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1164,14 +1164,21 @@ automation、replan、终态、inbox 和协调者覆盖规则,生成基础运
迁移后退役。CLI/Host 调用方直接使用类型化内核后,Python 公共函数、dataclass
及诊断 codec 退役。最终实现全部由 TypeScript 持有,不设 Python 规则回退。
适配器传递有界事实及诊断字符串,再应用
类型化配额补丁,不让来源数值或元数据经历 JSON 往返转换。回执绑定覆盖、后续
类型化配额补丁,不让来源数值或元数据经历 JSON 往返转换。回执绑定覆盖、剩余
route/action builder 和 effect 权限保留各自 owner。沿用既有 effective-action
词表及生成的 TS binding;canonical Python enum 等独立契约 owner 切换后退役。
TS 生产者验证器通过共享 guard fixture 执行真实 TS 分类器,并拒绝规则变更或
仅枚举 owner 的替代结果。这交付一个基础准入消费者的实现及语义一致性;完整 CLI
出现 p95 回退,性能验收保留 owner 复核门禁。整 Goal 迁移及 provider/默认配置
资格仍待完成。

Task-scoped `goal_route_hint` override 现在由同一个
`quota.run_decision` 响应返回。Python 从既有 task-orchestration source fact 投影
lane 数。TypeScript 持有 ready 状态检查、route 判定和协调说明。Python 重复实现的
`task_goal_route_hint` 判定已删除,只保留将有界补丁合并进已组装 hint 的步骤。
本改动不增加请求、provider 读取或 authority。其他 Goal route 与 primary-action
builder 仍是独立迁移工作;这不代表 quota read transaction 已完成,也不宣称性能提升。

**长历史传输边界。** Replan 历史仍由一个 TS owner 决策。小请求保留 inline
codec;较大的完整事实快照通过私有临时文件和摘要绑定的引用传递。同一 reducer
校验全部记录、agent 作用域内的 ACK 及重试身份;RPC 预算和展示窗口都不允许截断
Expand Down
5 changes: 3 additions & 2 deletions loopx/control_plane/goals/acceptance_authority.ts
Original file line number Diff line number Diff line change
Expand Up @@ -578,8 +578,9 @@ export async function inspectGoalAcceptance(
const state = authority.kind === "legacy" ? authority.state
: authority.owner_matches && authority.lifecycle.state === "active" ? authority.state : null;
const tasks = [...todos.entries()].filter(([key]) => todoId === undefined || key === todoId).map(([key, todo]) => ({
todo_id: key, todo_semantic_digest: goalAcceptanceTodoDigest(todo),
...(state ? acceptanceTask(key, todo, state) : {state: "unbound", criterion_ids: [], applicable: false}),
todo_semantic_digest: goalAcceptanceTodoDigest(todo),
...(state ? acceptanceTask(key, todo, state)
: {todo_id: key, state: "unbound", criterion_ids: [], applicable: false}),
}));
return source(store, {status: "loaded", provider_revision: head.provider_revision,
revision: state?.revision ?? null, contract_digest: state?.digest ?? null,
Expand Down
15 changes: 14 additions & 1 deletion loopx/control_plane/quota/decision_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class QuotaRunDecision:
state: str
quota: dict[str, Any]
replan_decision_allowed: bool
goal_route_hint_override: dict[str, Any] | None = None


def refine_quota_recommended_action(
Expand Down Expand Up @@ -272,6 +273,12 @@ def resolve_quota_run_decision(
) if replan_required and not (inbox_reply_due or inbox_material_review_due) else {}
repair_action = (stall_self_repair.get("effective_action")
if isinstance(stall_self_repair, dict) else None)
task_orchestration_lane_count = 0
if task_orchestration_contract is not None:
lanes = task_orchestration_contract.get("eligible_child_lanes")
if not isinstance(lanes, list):
lanes = task_orchestration_contract.get("eligible_peer_lanes")
task_orchestration_lane_count = len(lanes) if isinstance(lanes, list) else 0
result = effect_runtime_result("quota.run_decision", {
"normal_delivery_allowed": normal_delivery_allowed,
"recovery_delivery_allowed": recovery_delivery_allowed,
Expand All @@ -291,9 +298,15 @@ def resolve_quota_run_decision(
"inbox_material_review_due": inbox_material_review_due,
"terminal_no_followup": goal_frontier_is_terminal_no_followup(
projection=goal_frontier_projection),
"task_orchestration_lane_count": task_orchestration_lane_count,
"task_orchestration_contract": _guard_strings(
task_orchestration_contract, ("execution_state", "mode")),
})
patch = result.pop("quota_patch")
route_hint_override = result.pop("goal_route_hint_override", None)
# Only typed edits cross the wire; preserve source numbers and unmodified metadata.
return QuotaRunDecision(quota={**quota, **patch} if patch else quota, **result)
return QuotaRunDecision(
quota={**quota, **patch} if patch else quota,
goal_route_hint_override=route_hint_override,
**result,
)
30 changes: 29 additions & 1 deletion loopx/control_plane/quota/run_decision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface RunFacts {
inbox_material_review_due: boolean;
terminal_no_followup: boolean;
task_orchestration_contract: JsonObject | null;
task_orchestration_lane_count: number;
}

interface RunDecision extends JsonObject {
Expand All @@ -37,6 +38,7 @@ interface RunDecision extends JsonObject {
state: string;
quota_patch: JsonObject;
replan_decision_allowed: boolean;
goal_route_hint_override: JsonObject | null;
}

function text(value: unknown, label: string): string {
Expand All @@ -51,6 +53,8 @@ function optionalRecord(value: unknown, label: string): JsonObject | null {
}

function decodeRunFacts(params: JsonObject): RunFacts {
const taskOrchestrationContract = optionalRecord(params.task_orchestration_contract,
"task_orchestration_contract");
return {
normal_delivery_allowed: requireBoolean(params.normal_delivery_allowed, "normal_delivery_allowed"),
recovery_delivery_allowed: requireBoolean(params.recovery_delivery_allowed, "recovery_delivery_allowed"),
Expand All @@ -69,10 +73,18 @@ function decodeRunFacts(params: JsonObject): RunFacts {
inbox_reply_due: requireBoolean(params.inbox_reply_due, "inbox_reply_due"),
inbox_material_review_due: requireBoolean(params.inbox_material_review_due, "inbox_material_review_due"),
terminal_no_followup: requireBoolean(params.terminal_no_followup, "terminal_no_followup"),
task_orchestration_contract: optionalRecord(params.task_orchestration_contract, "task_orchestration_contract"),
task_orchestration_lane_count: nonNegativeCount(params.task_orchestration_lane_count,
"task_orchestration_lane_count"),
task_orchestration_contract: taskOrchestrationContract,
};
}

function nonNegativeCount(value: unknown, label: string): number {
if (!Number.isSafeInteger(value) || Number(value) < 0)
throw new EffectRuntimeRequestError(`${label} must be a non-negative safe integer`);
return Number(value);
}

function guardReason(guard: JsonObject | null, fallback: string): string {
return (guard ? text(guard.reason ?? "", "guard.reason") : "") || fallback;
}
Expand Down Expand Up @@ -178,6 +190,19 @@ function taskOrchestrationEffectiveAction(facts: RunFacts, decision: RunDecision
return [decision.effective_action, decision.reason];
}

function taskOrchestrationRouteHint(contract: JsonObject | null, laneCount: number): JsonObject | null {
if (!contract || (text(contract.execution_state ?? "", "execution_state") || "ready") !== "ready") return null;
return {
omit_current_agent_next_action: true,
kind: "task_orchestration",
route_decision: "coordinate_task_bundle",
reason: contract.mode === "adaptive"
? "task-scoped coordinator may spawn admitted child lanes"
: "task-scoped coordinator must activate/resume eligible peer lanes",
peer_lane_count: laneCount,
};
}

/** Compose base quota admission after source reads; receipt-bound overlays keep their owners. */
export function resolveQuotaRunDecision(params: JsonObject): JsonObject {
const facts = decodeRunFacts(params);
Expand All @@ -188,11 +213,14 @@ export function resolveQuotaRunDecision(params: JsonObject): JsonObject {
capability_repair_allowed: false, workspace_repair_allowed: false,
should_run: false, effective_action: EffectiveAction.QUOTA_SKIP,
reason: facts.reason, state: facts.state, quota_patch: {}, replan_decision_allowed: false,
goal_route_hint_override: null,
};
applyDeliveryGuards(facts, decision);
decision.effective_action = quotaEffectiveAction(facts, decision);
applyGoalOverrides(facts, decision);
applyInboxOverrides(facts, decision);
[decision.effective_action, decision.reason] = taskOrchestrationEffectiveAction(facts, decision);
decision.goal_route_hint_override = taskOrchestrationRouteHint(
facts.task_orchestration_contract, facts.task_orchestration_lane_count);
return decision;
}
6 changes: 3 additions & 3 deletions loopx/control_plane/quota/should_run_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@
)
from ..quota.task_orchestration import (
PEER_COORDINATION_BLOCKED_ACTION,
apply_task_route_hint_override,
attach_task_orchestration_payload,
task_goal_route_hint,
task_orchestration_contract_is_actionable,
task_orchestration_requires_material_change_stop,
)
Expand Down Expand Up @@ -1278,9 +1278,9 @@ def _resolve_quota_should_run_route(
latest_run_recommended_action=latest_run_recommended_action_text,
selected_recommended_action=selected_recommended_action,
)
goal_route_hint = task_goal_route_hint(
goal_route_hint = apply_task_route_hint_override(
goal_route_hint,
prepared.task_orchestration_contract,
run_decision.goal_route_hint_override,
)
payload_work_lane_contract = _payload_work_lane_contract(
prepared.work_lane_contract,
Expand Down
45 changes: 17 additions & 28 deletions loopx/control_plane/quota/task_orchestration.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,23 @@ def task_orchestration_contract_is_actionable(
return str(contract.get("execution_state") or "ready") == "ready"


def apply_task_route_hint_override(
hint: dict[str, Any] | None,
override: dict[str, Any] | None,
) -> dict[str, Any] | None:
"""Apply the route patch returned by the TypeScript decision owner."""
if hint is None or override is None:
return hint
projected_hint = {
key: value for key, value in hint.items()
if not (override.get("omit_current_agent_next_action") is True
and key == "current_agent_next_action")
}
projected_hint.update({key: value for key, value in override.items()
if key != "omit_current_agent_next_action"})
return projected_hint


def task_orchestration_requires_material_change_stop(
contract: dict[str, Any] | None,
*,
Expand Down Expand Up @@ -145,34 +162,6 @@ def apply_task_orchestration_contract(
return contract, _task_orchestration_work_lane_contract(contract)


def task_goal_route_hint(
goal_route_hint: dict[str, Any] | None,
contract: dict[str, Any] | None,
) -> dict[str, Any] | None:
if not contract or not isinstance(goal_route_hint, dict):
return goal_route_hint
if not task_orchestration_contract_is_actionable(contract):
return goal_route_hint
lanes = contract.get("eligible_child_lanes")
if not isinstance(lanes, list):
lanes = contract.get("eligible_peer_lanes")
return {
**{
key: value
for key, value in goal_route_hint.items()
if key != "current_agent_next_action"
},
"kind": "task_orchestration",
"route_decision": "coordinate_task_bundle",
"reason": (
"task-scoped coordinator may spawn admitted child lanes"
if contract.get("mode") == "adaptive"
else "task-scoped coordinator must activate/resume eligible peer lanes"
),
"peer_lane_count": len(lanes) if isinstance(lanes, list) else 0,
}


def attach_task_orchestration_payload(
payload: dict[str, Any],
contract: dict[str, Any] | None,
Expand Down
31 changes: 31 additions & 0 deletions tests/control_plane/test_quota_run_decision.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
QuotaRunDecision,
resolve_quota_run_decision,
)
from loopx.control_plane.quota.task_orchestration import apply_task_route_hint_override


def _resolve(**overrides: Any) -> QuotaRunDecision:
Expand Down Expand Up @@ -176,6 +177,36 @@ def test_task_orchestration_refines_normal_run_action() -> None:
assert decision.should_run is True
assert decision.normal_delivery_allowed is True
assert decision.effective_action == "coordinate_task_bundle"
assert decision.goal_route_hint_override == {
"omit_current_agent_next_action": True,
"kind": "task_orchestration",
"route_decision": "coordinate_task_bundle",
"reason": "task-scoped coordinator must activate/resume eligible peer lanes",
"peer_lane_count": 0,
}
decision = _resolve(task_orchestration_contract={"execution_state": "ready", "mode": "adaptive",
"eligible_child_lanes": [{}, {}]})
assert decision.goal_route_hint_override["peer_lane_count"] == 2


def test_goal_route_hint_applies_only_the_typed_owner_patch() -> None:
hint = {"kind": "agent_lane_synthesis", "current_agent_next_action": {"todo_id": "todo-a"},
"has_durable_next_action": True}
patched = apply_task_route_hint_override(hint, {
"omit_current_agent_next_action": True,
"kind": "task_orchestration",
"route_decision": "coordinate_task_bundle",
"reason": "task-scoped coordinator may spawn admitted child lanes",
"peer_lane_count": 2,
})
assert patched == {
"kind": "task_orchestration",
"route_decision": "coordinate_task_bundle",
"reason": "task-scoped coordinator may spawn admitted child lanes",
"peer_lane_count": 2,
"has_durable_next_action": True,
}
assert hint["current_agent_next_action"] == {"todo_id": "todo-a"}


@pytest.mark.parametrize(
Expand Down
31 changes: 27 additions & 4 deletions tests/control_plane_ts/fixtures/quota_run_decision.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"inbox_reply_due": false,
"inbox_material_review_due": false,
"terminal_no_followup": false,
"task_orchestration_lane_count": 0,
"task_orchestration_contract": null
},
"base_result": {
Expand All @@ -31,7 +32,8 @@
"reason": "eligible",
"state": "eligible",
"quota_patch": {},
"replan_decision_allowed": false
"replan_decision_allowed": false,
"goal_route_hint_override": null
},
"cases": [
{
Expand Down Expand Up @@ -324,7 +326,14 @@
},
"expected": {
"effective_action": "coordinate_task_bundle",
"reason": "the task coordinator may use admitted child lanes before its own worker-lane delivery"
"reason": "the task coordinator may use admitted child lanes before its own worker-lane delivery",
"goal_route_hint_override": {
"omit_current_agent_next_action": true,
"kind": "task_orchestration",
"route_decision": "coordinate_task_bundle",
"reason": "task-scoped coordinator may spawn admitted child lanes",
"peer_lane_count": 0
}
}
},
{
Expand All @@ -337,7 +346,14 @@
},
"expected": {
"effective_action": "coordinate_task_bundle",
"reason": "the explicitly selected task coordinator must activate or resume eligible peer lanes before doing its own worker-lane delivery"
"reason": "the explicitly selected task coordinator must activate or resume eligible peer lanes before doing its own worker-lane delivery",
"goal_route_hint_override": {
"omit_current_agent_next_action": true,
"kind": "task_orchestration",
"route_decision": "coordinate_task_bundle",
"reason": "task-scoped coordinator must activate/resume eligible peer lanes",
"peer_lane_count": 0
}
}
},
{
Expand All @@ -361,7 +377,14 @@
},
"expected": {
"effective_action": "operator_inbox_material_review_due",
"reason": "captured unaddressed operator-inbox material is pending bounded review"
"reason": "captured unaddressed operator-inbox material is pending bounded review",
"goal_route_hint_override": {
"omit_current_agent_next_action": true,
"kind": "task_orchestration",
"route_decision": "coordinate_task_bundle",
"reason": "task-scoped coordinator may spawn admitted child lanes",
"peer_lane_count": 0
}
}
},
{
Expand Down
1 change: 1 addition & 0 deletions tests/control_plane_ts/goal_acceptance_authority.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ for (const provider of providers) {
assert.deepEqual(await head(store), after, "task-scoped planning has no provider write");
assert.equal(((inspection.contract as JsonObject).criteria as JsonObject[])[0].validation_timeout_seconds, 5);
assert.ok((inspection.tasks as JsonObject[]).every(task => typeof task.todo_semantic_digest === "string"));
assert.ok((inspection.tasks as JsonObject[]).every(task => typeof task.todo_id === "string"));
const projection = projectGoalAcceptance(after.head, goal);
assert.equal(projection.status, "held");
assert.deepEqual(projection.held_todo_ids, ["todo_second"]);
Expand Down
Loading
Loading