Skip to content
Closed
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
20 changes: 16 additions & 4 deletions docs/architecture/rfcs/hierarchical-agent-stride-control-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -762,17 +762,29 @@ these facts do not change the admitted context/basis identity. Changed source
requires rereading within the original Turn. Page coordinates persist with the
decision into subsequent review; node-filtered/planner detail routes remain
outside this bounded citation path. No separate receipt store is introduced.
The enabled review also carries the prior decision's existing `todo_delta`
The replan context also carries the prior decision's existing `todo_delta`
targets in `decision_followthrough.planned_work`: current canonical status and
claim, plus references to causally later observations of that exact work item.
Legacy descriptive Todo deltas remain readable with unresolved linkage; an
overlong reference is never truncated into a different Todo identity.
Missing Todo sources and omitted work remain explicit; a missing observation
does not prove non-execution, and Todo completion does not prove objective gain.
Related observations survive unrelated recent activity in the bounded window.
The same bounded followthrough is included in `stride_control` so compact Host
envelopes expose it without requiring another full-context read. Historical
decision identities and off-mode output remain unchanged.
Generic followthrough is available with stride off as well: `result_counts`
separates advanced, unchanged, blocked and terminal observations, while visible
rows retain their result class and delivery outcome. The compatibility
`recorded_progress_count` is an observation count, never successful work.
Historical decision identities and stride admission/settlement gates remain
unchanged; off-mode context now includes this feedback without enabling stride.

The [captured replan reader](../../reference/protocols/turn-envelope-v0.md#captured-replan-reads--捕获后的重规划读取)
separates state review from authoring on one immutable decision snapshot.
Cumulative acceptance uses lossless content-bound detail reads, and Explore
receives a separate context increment. Existing uncaptured callers retain their
full delivery. File/SQLite source tests and populated packet budgets qualify
transport and writer continuity; installed adoption, real model decisions and
matched outcome/cost benefit remain unqualified. This introduces no new planning
receipt, model checkpoint or requirement to change direction.

The next-review input also exposes causally later ordinary writebacks for the
declared work in `ordinary_work`, with per-Todo `ordinary_evidence_refs`. Its
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -632,14 +632,22 @@ revision、考虑的 finding 与适用/暂缓等理由,不建新图或第二
拒绝缺少复盘、错误引用以及过期或不可用依据的错误声明,校验提案结构和来源,
不能证明研究已执行或有收益。

启用策略后,`decision_followthrough.planned_work` 将上次决定中既有 `todo_delta`
replan context 中的 `decision_followthrough.planned_work` 将上次决定中既有 `todo_delta`
指向的 Todo 与当前规范状态、认领人和该工作项在决定之后的观测引用一起返回。
Todo 来源缺失和省略数量明确保留;缺少观测不等于没有执行,Todo 完成也不等于
目标收益。历史描述性 Todo delta 保持可读并注明关联未解析;过长引用不会截断成
另一个 Todo 的身份。相关观测不会被大量较新的无关活动挤出有限窗口。
同一份有界反馈进入
`stride_control`,紧凑 Host envelope 可直接消费,避免为这些信息再读完整上下文。
历史决定的引用身份及 off 模式输出不变。
通用执行回顾在 stride 关闭时也可读取:`result_counts` 区分推进、未变、阻塞和
终态观测,明细保留结果分类及交付结果。兼容字段 `recorded_progress_count` 表示
观测数量,不表示成功工作。历史决定引用及 stride 准入/结算门禁不变;off 模式
新增反馈上下文,但不启用 stride。

[捕获后的重规划读取](../../reference/protocols/turn-envelope-v0.md#captured-replan-reads--捕获后的重规划读取)
把状态审视和写回格式分开,复用同一不可变决策快照。累计验收通过内容绑定的明细
读取完整保留,Explore 使用独立的上下文增量预算;未捕获快照的调用仍完整投递。
File/SQLite 源码测试和真实规模 packet 预算验证传输与写回连续性;已安装采用、真实
模型决策及可比成果/成本收益仍待资格化。不新增规划回执、模型 checkpoint 或强制
改变方向的要求。

下一轮输入还通过 `ordinary_work` 与各 Todo 的 `ordinary_evidence_refs` 返回已
声明工作在决定之后的普通回写。详情最多六项,保留总数、省略数和稳定 history
Expand Down
80 changes: 80 additions & 0 deletions docs/reference/protocols/turn-envelope-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,86 @@ CLI from becoming another reader of the legacy guidance field.
事实仍在当前包内,不需再次执行 guard。不同副本和既有详细视图保留;原始决定与
capture 不变。动作维度等价不意味着不同渲染可以共用原始 source hash。

### Captured replan reads / 捕获后的重规划读取

For a successful replan with `--decision-output-dir` or `--decision-output-root`,
the CLI and TurnEnvelope expose `replan_action_packet.review` followed by
`writeback`. Both are executable `quota replan-view` commands bound to the same
captured JSON value and source hash. The first read supplies goal context,
previous decision/results, planning dependencies and evidence references; the
second supplies the existing authoring shape and settlement commands. No read
runs another guard, writes a receipt or authorizes work. There is no additional
read acknowledgement, mandatory model call or prescribed route change.

Captured reads retain the caller's explicit `--cli-bin` route, including later
acceptance and Explore reads; an ambient executable cannot silently replace it.
The review stage provides structured facts without a prescribed diagnostic
method. Writeback omits filled-in Vision/stride examples while retaining field
limits, legal options, source bindings and settlement rules. Stride exposes its
required field names and basis options independently of examples. The unchanged
full capture remains available for optional examples and source inspection.
This intentionally reduces advisory prompting; it does not remove acceptance,
authority or stop obligations, nor demonstrate better autonomous decisions.

Cumulative outcome requirements are indexed by exact content hash. Every
objective, revision and requirement count remains visible; the acceptance read
returns the complete original outcome. Identical IDs with different revisions
or evidence remain distinct. Equal context/horizon copies share references;
differing goal scopes remain separate. The full capture retains all evidence,
legacy guidance and authoring examples. Explore has an optional, separately
readable basis; unavailable evidence remains unavailable. These views do not
assess acceptance, infer execution from counts or make a dependency global.

`quota replan-view --decision-file <file> --source-hash <hash>` defaults to
`--replan-stage review`; `writeback`, `acceptance --outcome-ref <ref>` and
`explore` read the corresponding original-source detail. Missing/mutated sources
fail without guard replay. Existing uncaptured calls and native journal captures
without the CLI read route retain their prior delivery. The existing generic
followthrough is now available with stride off; its result-class counts and
observations remain evidence, not successful-work or goal-gain verdicts.

对使用 `--decision-output-dir` 或 `--decision-output-root` 的成功 replan,CLI 和
TurnEnvelope 先给出 `review` 状态读取,再给出 `writeback` 格式读取。两步绑定同一
快照和来源哈希,不重新准入、不新增回执或授权,也不强制换路线。累计验收按完整
内容哈希建立索引:每个目标、版本及要求数量可见,明细完整读回;相同 ID 的不同
版本不会覆盖。相同的目标上下文副本共享引用,不同范围保留。Explore 明细单独按需
读取;不可用保持不可用。完整快照仍保存原指导、示例和证据。没有捕获或没有 CLI
读取路径的原生 journal 保持原交付方式。通用执行回顾不再依赖 stride 开关;分类
计数只表示观测,不等于工作成功或目标收益。

捕获后的读取沿用调用方显式选择的 `--cli-bin`,后续验收和 Explore 读取也不会
悄悄切换到环境中的其他版本。复盘视图提供结构化事实,不预设诊断方法;写回视图
移除预填的 Vision/stride 答案示例,保留字段限制、合法选项、来源绑定和结算规则。
stride 的必需字段与 basis 选项独立展示,完整快照仍可用于按需查看示例与源材料。
这是有意减少建议性提示,不删除验收、权限或停止义务,也不证明自主决策质量提升。

Regression budgets use compact UTF-8 JSON, separately from compute quota and
provider tokens. The synthetic workload uses a real append index with 1,500
records, 21 later observations, 24 cumulative outcomes and a populated Explore
log. Limits protect default input while exact details remain readable:

| View | Regression allocation |
| --- | --- |
| Replan entry packet | 2 KiB |
| Populated history review | 16 KiB |
| Planning inventory increment | 8 KiB |
| Cumulative acceptance index increment | 12 KiB |
| Explore increment in entry / review | 128 B / 768 B |
| Explore detail / writeback | 8 KiB / 16 KiB |

The whole-envelope differential also prevents a large acceptance copy moving to
another hot carrier. These are fixture regression allocations, not runtime
truncation or refusal limits; the existing 8 KiB envelope warning remains.
File/SQLite CLI tests cover capture → reads → existing writeback, hash rejection
and unchanged state during reads. They do not establish model choice quality,
installed adoption, token savings or matched long-horizon benefit.

大小回归使用紧凑 UTF-8 JSON,与算力 quota 和 provider token 分开。通用 review、
累计验收索引和 Explore 分别约束增量,同时检查整个 envelope,防止把大副本挪到
另一处热输入。预算不在运行时截断或拒绝合法内容,原 8 KiB envelope 警告保留。
File/SQLite CLI 验证快照、分步读取、既有写回和哈希拒绝,不据此宣称模型决策、
已安装采用、token 节省或长程收益改善。

### Native Turn Host capture

Executing `turn run-once --execute` now saves the original full decision before
Expand Down
21 changes: 13 additions & 8 deletions loopx/cli_commands/quota.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from __future__ import annotations

import argparse
import json
import time
from collections.abc import Callable, Mapping
from pathlib import Path

from .quota_capture import bind_capture_selection_transport, capture_decision, handoff_decision, prepare_decision_capture
from .quota_capture import bind_capture_selection_transport, capture_decision, handoff_decision, handle_replan_view, prepare_quota_capture
from ..usage_goal import observe_quota_result

from ..capabilities.explore.composition_frontier import (
Expand Down Expand Up @@ -411,6 +412,9 @@ def _project_quota_cli_payload(
if args.quota_command in {"status", "plan"}:
return compact_quota_plan_cli_payload(payload, detail_sections=detail_sections)
if args.quota_command == "should-run":
if captured_decision_path and "vision" not in detail_sections:
from ..control_plane.quota.turn_envelope import _turn_envelope_result
payload = _turn_envelope_result("replan_cli_view", payload=payload)
return compact_quota_should_run_cli_payload(
payload,
include_todo_summary_detail="agent-todos" in detail_sections,
Expand Down Expand Up @@ -464,6 +468,11 @@ def _emit_quota_result(
started_at=usage_quota_started,
)
bind_capture_selection_transport(payload, args)
if capture_directory is not None and payload.get("replan_action_packet"):
from ..command_invocation import loopx_cli_argv

payload = {**payload, "replan_read_path": str(capture_directory / "decision.json"),
"replan_read_argv": loopx_cli_argv()}
try:
capture_decision(capture_directory, payload)
if payload.get("ok") is True:
Expand Down Expand Up @@ -504,6 +513,8 @@ def handle_quota_command(
append_cli_rollout_event: RolloutEventAppender,
capture_directory: Path | None = None,
) -> int:
if args.quota_command == "replan-view":
return handle_replan_view(args, print_payload)
usage_quota_started = time.time_ns() // 1_000_000
heartbeat_turn_id: str | None = None
heartbeat_receipt_existing: dict[str, object] | None = None
Expand All @@ -518,13 +529,7 @@ def handle_quota_command(
context: QuotaCommandContext | None = None
goal_ref: dict[str, str] | None = None
try:
if capture_directory is None and (
getattr(args, "decision_output_dir", None) is not None
or getattr(args, "decision_output_root", None) is not None
or getattr(args, "decision_handoff_socket", None) is not None
):
validate_quota_command_context_request(args)
capture_directory = prepare_decision_capture(args)
capture_directory = prepare_quota_capture(args, capture_directory)
goal_ref, turn_start_hook_dispatch, context = (
_prepare_quota_command_execution(
args,
Expand Down
42 changes: 42 additions & 0 deletions loopx/cli_commands/quota_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,28 @@
import shlex
import socket
import tempfile
from collections.abc import Callable
from pathlib import Path

from ..control_plane.effect_runtime import EffectRuntimeRejected
from ..control_plane.quota.error_codes import QuotaCommandValidationError, QuotaDecisionTransportError
from ..control_plane.turn_driver.decision_capture import validate_handoff_socket


def prepare_quota_capture(args: argparse.Namespace, directory: Path | None) -> Path | None:
"""Validate transport options before allocating a new guard capture."""
if directory is None and (
getattr(args, "decision_output_dir", None) is not None
or getattr(args, "decision_output_root", None) is not None
or getattr(args, "decision_handoff_socket", None) is not None
):
from .quota_context import validate_quota_command_context_request

validate_quota_command_context_request(args)
return prepare_decision_capture(args)
return directory


def prepare_decision_capture(args: argparse.Namespace) -> Path | None:
requested = getattr(args, "decision_output_dir", None)
root = getattr(args, "decision_output_root", None)
Expand Down Expand Up @@ -123,3 +139,29 @@ def handoff_decision(directory: Path | None, socket_path: str | None) -> None:
"Decision handoff failed after guard evaluation; inspect the original "
f"Turn receipt and {path}. Do not blindly rerun the guard."
) from exc


def read_replan_view(args: argparse.Namespace) -> dict:
"""Read a captured observation only; no registry, provider, guard or receipts."""
from ..control_plane.quota.turn_envelope import _turn_envelope_result

if not args.decision_file or not args.source_hash:
raise ValueError("replan-view requires --decision-file and --source-hash")
path = Path(args.decision_file).expanduser()
with path.open(encoding="utf-8") as stream:
payload = json.load(stream)
return _turn_envelope_result("replan_view", payload=payload, source_hash=args.source_hash,
stage=args.replan_stage, outcome_ref=args.outcome_ref)


def handle_replan_view(
args: argparse.Namespace,
print_payload: Callable[[dict[str, object], str, Callable[[dict[str, object]], str]], None],
) -> int:
"""Render the captured read without entering live quota dispatch or recovery."""
try:
view = read_replan_view(args)
except (OSError, ValueError, EffectRuntimeRejected) as exc:
view = {"ok": False, "reason": str(exc)}
print_payload(view, args.format, lambda value: json.dumps(value, ensure_ascii=False, indent=2))
return 0 if view["ok"] else 1
6 changes: 6 additions & 0 deletions loopx/cli_commands/quota_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def register_quota_command(
"status",
"plan",
"should-run",
"replan-view",
"monitor-poll",
"scheduler-ack",
"scheduler-ack-current",
Expand All @@ -37,6 +38,11 @@ def register_quota_command(
default="status",
help="Use status for all groups, plan for next-turn groups, should-run for one goal, monitor-poll for no-spend quiet poll evidence, scheduler-ack for successful Codex App RRULE state, scheduler-fail-current to suppress a repeated failed host update pair, spend-slot for accounting, or void-slot for a non-destructive accounting correction.",
)
quota_parser.add_argument("--decision-file", help="Original captured decision for read-only replan-view.")
quota_parser.add_argument("--outcome-ref", help="Exact captured acceptance outcome reference for replan-view.")
quota_parser.add_argument("--source-hash", help="Original source_decision_hash for replan-view.")
quota_parser.add_argument("--replan-stage", choices=["review", "writeback", "acceptance", "explore"], default="review",
help="Read decision context before opening its writeback format.")
quota_parser.add_argument(
"--goal-id",
help="Goal id to check. Optional for status/plan (omit for all goals); required for should-run, scheduler ACK/failure, spend, and void. A scoped status/plan ranks only the selected goal, not the global next turn.",
Expand Down
Loading
Loading