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
7 changes: 5 additions & 2 deletions docs/heartbeat-automation-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -802,8 +802,11 @@ For every automatic heartbeat turn, the agent-facing checklist is:
15. Work bounded when `should_run=true`; a coherent implementation/test/doc/state
batch is preferred over a tiny substep when scope and validation are clear.
16. Validate before reporting.
17. After validation/writeback, refresh accountable progress with explicit
delivery scale/outcome hints, then spend exactly once against that record.
17. After validation/writeback, follow the current typed settlement plan. An
exact committed receipt-bound monitor poll already closes that Turn with no
accountable refresh or quota spend, including a material poll that releases
an independent successor. Other accountable delivery refreshes use explicit
scale/outcome hints and spend exactly once against that record.
18. Refresh state-only metadata after spend only when needed; never emit another
accountable progress refresh after accounting.
19. Report compactly.
Expand Down
13 changes: 9 additions & 4 deletions docs/quota-allocation.md
Original file line number Diff line number Diff line change
Expand Up @@ -734,10 +734,15 @@ loopx configure-goal --goal-id <goal-id> \

This suppresses that peer's advancement, autonomous replan, repair, fallback,
and new-topic lanes while preserving due `continuous_monitor` todos and verified
direct operator replies. A future or unchanged monitor stays quiet and no-spend;
a due monitor may spend only after a validated material transition. Other peers
remain active. Use `--clear-agent-work-mode <agent-id>` (or set `=active`) to
resume ordinary advancement.
direct operator replies. A future monitor stays quiet; a committed monitor poll
is the Turn's no-spend closeout whether unchanged or material. A material poll
may atomically release an independent advancement successor, whose later
delivery has its own quota identity. Same-Turn readback and prior-Turn recovery
accept the same exact committed effect, including the shipped turn-only receipt;
a preview or a row with missing or mismatched commit metadata cannot close the
Turn. Other peers remain active. Use
`--clear-agent-work-mode <agent-id>` (or set `=active`) to resume ordinary
advancement.

The read model exposes that derivation as
`goal_frontier_projection.terminal_state={kind:no_followup, derived:true,
Expand Down
13 changes: 7 additions & 6 deletions docs/state-interaction-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -827,12 +827,13 @@ or reattributing its delivery workspace. An identical retry returns `replay`
with the saved checkpoint; it does not append again. A changed satisfied
decision, changed delivery payload, or a missing checkpoint superseded by a
later same-Agent vision is rejected with no write. Dry-run previews do not
repair receipts or append history. A receipt-bound material monitor poll with
no prior refresh/checkpoint may complete its missing workspace writeback with
next-action and vision together, through the normal vision/replan validation.
This first-closeout compatibility path preserves the poll outcome and rejects
unrelated mutations; subsequent retries use the same strict replay/conflict
rules. Other missing-workspace repairs precede checkpoint supplementation.
repair receipts or append history. Current receipt-bound monitor Turns close on
the exact committed poll, including material polls that release an independent
successor; they do not require an accountable refresh, workspace supplement or
quota spend. The retained material-monitor refresh recovery branch is
compatibility-only for older phase producers and preserves the original poll
outcome while rejecting unrelated mutations. Other missing-workspace repairs
precede checkpoint supplementation.

Do not repeat implementation, manufacture a successor, or open another Turn
just to repair this checkpoint. Keep the ordinary one-spend settlement order.
Expand Down
5 changes: 3 additions & 2 deletions loopx/control_plane/heartbeat/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
"具体user todo未投影,需修复LoopX状态投影;静默时内部修复。"
)
HEARTBEAT_VISION_WRITEBACK_RULE_SHORT = (
"writeback: no-change=`surface_only`/no spend;material=实际outcome+vision决定;"
"缺则同turn按返回命令补齐再terminal;unchanged→真实`--vision-unchanged-reason`。"
"writeback: 本轮精确monitor-poll提交→不refresh/spend;"
"其余no-change=surface_only/no spend;material=outcome+vision;"
"缺则同轮按返回命令补齐再terminal;unchanged→真实--vision-unchanged-reason。"
)
REWARD_MEMORY_OUTCOME_RULE = (
"`reward_memory_recall.experiment.automatic_ingest=true`: reusable Todo outcomes "
Expand Down
23 changes: 19 additions & 4 deletions loopx/control_plane/quota/settlement_phase.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
import type { SettlementIdentity } from "../effect_program.ts";

/** Both same-Turn readback and prior-Turn recovery accept the shipped effect identities. */
export function isCommittedMonitorPollEffect(
effectId: unknown,
identity: Pick<SettlementIdentity, "goal_id" | "agent_id" | "turn_instance_id" | "todo_id">,
): boolean {
if (!identity.todo_id) return false;
const base = `quota-monitor-poll:${identity.goal_id}:${identity.agent_id}:${identity.turn_instance_id}`;
return effectId === base || effectId === `${base}:todo:${identity.todo_id}`;
}

export const RECEIPT_BOUND_MONITOR_PHASES = [
"poll_due",
"settlement_pending",
Expand All @@ -17,10 +29,13 @@ export function receiptBoundMonitorPhase(
state: ReceiptBoundMonitorSettlementState,
): ReceiptBoundMonitorPhase {
if (!state.poll_present) return "poll_due";
if (!state.material_change) return "settled";
return state.durable_writeback_present && state.quota_spend_present
? "settled"
: "settlement_pending";
// The committed monitor-poll is the durable no-spend closeout for this
// monitor Turn. A material observation may atomically release an independent
// successor, but it never upgrades the observe-only monitor into an
// accountable delivery or quota-spend identity. Keep the extra inputs in the
// cross-runtime request for compatibility with older callers; they no longer
// decide this phase.
return "settled";
}

export const RECEIPT_BOUND_REPLAY_PHASES = [
Expand Down
4 changes: 3 additions & 1 deletion loopx/control_plane/quota/settlement_readback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
type DeliveryWorkspaceCausality,
} from "./settlement_workspace_causality.ts";
import {
isCommittedMonitorPollEffect,
receiptBoundMonitorPhase,
receiptBoundReplayPhase,
} from "./settlement_phase.ts";
Expand Down Expand Up @@ -735,7 +736,8 @@ export async function readQuotaSettlement(value: unknown): Promise<JsonObject> {
optionalString(run.goal_id) === identity.goal_id &&
optionalString(run.agent_id) === identity.agent_id &&
optionalString(run.turn_instance_id) === identity.turn_instance_id &&
(!identity.todo_id || normalizeTodoId(run.todo_id) === identity.todo_id)
normalizeTodoId(run.todo_id) === identity.todo_id &&
isCommittedMonitorPollEffect(jsonObject(run.quota_monitor_poll_commit)?.effect_id, identity)
) ?? null;
const nestedCausality = typeof receiptDetails.delivery_workspace_causality === "object" &&
receiptDetails.delivery_workspace_causality !== null &&
Expand Down
21 changes: 8 additions & 13 deletions loopx/control_plane/quota/unsettled_host_turn_recovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
requireNonEmptyString,
} from "../runtime_decode.ts";
import { readGoalHeartbeatReceipts } from "../rollout_receipt_log.ts";
import { isCommittedMonitorPollEffect } from "./settlement_phase.ts";
import {
heartbeatReceiptBinding,
heartbeatReceiptFactFromEvent,
Expand Down Expand Up @@ -364,16 +365,6 @@ function decodeMissingReceipts(value: unknown): string[] {
return [...expected];
}

function committedMonitorPollEffectIds(
candidateBinding: PriorHostTurnCloseoutCandidate,
goalId: string,
agentId: string,
): string[] | null {
if (candidateBinding.binding_kind !== "todo") return null;
const base = `quota-monitor-poll:${goalId}:${agentId}:${candidateBinding.prior_turn_instance_id}`;
return [base, `${base}:todo:${candidateBinding.binding_id}`];
}

function acceptedLifecycleCloseout(todo: CandidateTodoFacts | null): AcceptedCloseout | null {
if (todo === null) return null;
if (
Expand Down Expand Up @@ -442,15 +433,19 @@ export function reduceUnsettledHostTurnRecovery(value: unknown): JsonObject {
);
}
const todo = bindingFacts.todo;
const acceptedEffectIds = committedMonitorPollEffectIds(selected, goalId, agentId);
const committedEffectId = bindingFacts.committedMonitorPoll === null
? null
: optionalHeartbeatString(bindingFacts.committedMonitorPoll.effect_id);
if (
acceptedEffectIds !== null &&
selected.binding_kind === "todo" &&
todo?.task_class === MONITOR_TASK_CLASS &&
committedEffectId !== null &&
acceptedEffectIds.includes(committedEffectId)
isCommittedMonitorPollEffect(committedEffectId, {
goal_id: goalId,
agent_id: agentId,
turn_instance_id: selected.prior_turn_instance_id,
todo_id: selected.binding_id,
})
) {
return {
schema_version: UNSETTLED_HOST_TURN_RECOVERY_RESULT_SCHEMA,
Expand Down
6 changes: 3 additions & 3 deletions loopx/semantics/vocabulary_v0.json
Original file line number Diff line number Diff line change
Expand Up @@ -613,9 +613,9 @@
"settled"
],
"value_notes": {
"poll_due": "Emitted when no quota monitor poll run exists for this settlement identity of goal, agent, turn instance and, where bound, Todo. The observation record itself is missing, so the system does not yet know whether anything is owed. This is what distinguishes it from the replay vocabulary's open, where the observation exists but its completion receipt does not.",
"settlement_pending": "Emitted when a monitor poll exists and reports a material change, but the durable writeback and quota spend readbacks have not both resolved without failure. A material poll owes receipts and at least one is still absent or failing.",
"settled": "Emitted on two disjoint routes: a poll that reports no material change owes nothing and is settled on arrival with no receipt at all, or a material poll whose durable writeback and quota spend readbacks both resolved. The first route is the shortcut the replay vocabulary deliberately lacks."
"poll_due": "Emitted when no committed quota monitor poll matches the exact goal, agent, turn and Todo identity. A matching observation row without its exact native commit effect does not prove closeout. This is what distinguishes it from the replay vocabulary's open, where the observation exists but its completion receipt does not.",
"settlement_pending": "Compatibility value accepted from older phase producers. The current owner no longer emits it once an exact monitor-poll commit is present, because monitor observation is a no-spend closeout regardless of whether it releases a successor.",
"settled": "Emitted whenever the exact quota monitor-poll commit exists for the settlement identity. Unchanged and material observations both close the observe-only monitor Turn without accountable refresh or quota spend; a material poll may atomically release an independent advancement successor."
}
},
"receipt_bound_replay_phase": {
Expand Down
Loading
Loading