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
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ touch, mention it in the PR instead of fixing it there.
| --- | --- | --- | --- |
| `python-tests.yml` | every PR | yes (`merge-gate`) | lint, mypy, sharded pytest, TypeScript core and coverage, minimum Node.js, Windows PowerShell, dashboard presentation |
| `dco.yml` | every PR | yes (`Sign-off`) | `Signed-off-by` on contribution commits; verified GitHub-generated two-parent merges are exempt |
| `ci-maintenance.yml` | closed or updated PR (`pull_request_target`, trusted base code only) | no | cancels obsolete Python qualification runs after rechecking the PR and source branch |
| `dependency-review.yml` | every PR | no | dependency changes introduced by the PR |
| `postgresql-integration.yml` | control-plane or npm lockfile paths | no | PostgreSQL authority store and service on a temporary instance |
| `package-smoke.yml` | extension package paths | no | extension packages install, entrypoints, and example schemas |
Expand Down
18 changes: 18 additions & 0 deletions docs/product/release-readiness.md
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,24 @@ path, and canary route rather than as a user-facing release baseline.
SQLite qualification remain unqualified. No paired-version benchmark uplift
or isolated Astra causal effect is claimed.

- `v1.4.1` on 2026-10-15: workspace visibility, semantic replan and recovery
hardening at frozen commit `4f27801c4e26fd51246d352eada72c98f8e7e657`.
The [published release](https://github.com/loopx-project/loopx/releases/tag/v1.4.1)
records nineteen bilingual operating entries and concrete community credits.
GitHub/PyPI packages, four desktop installers, the signed macOS update feed,
`desktop-stable`, source `stable`, the website download path and the personal
illustrated guide were independently read back. An actual PyPI
1.4.0-to-1.4.1 upgrade preserved existing work; package hashes and source bytes
matched the immutable product tag. Reviewed publication-fixture recovery did
not move that tag. At the final source, 515 public smokes and 2,213 affected
Python checks passed, with five explicit native-environment skips; this was
not a fresh full-tree Python sweep. Doubao Evolving/high completed the fixed
22-scenario, two-repeat portfolio and six contrasts with zero failures or
skips. Mac artifacts retain ad-hoc signing without Apple notarization;
Windows artifacts were verified without native client execution. No paired
benchmark, sustained scientific continuation or isolated model causal uplift
is claimed.

When a new public release is promoted, add it here only after the matching tag,
release note, stable ref, update path, and focused release canary agree.

Expand Down
16 changes: 16 additions & 0 deletions docs/reference/contracts/interface-budget-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ Do not abbreviate admission, continuation, scope, safety or settlement instructi
solely to fit a historical character count, or copy dynamic quota decisions into
the static prompt.

The same two-scope Codex App brief fixture measures 4,284 normalized body
characters on v1.4.1 and 4,447 with the shared stop/readback rule: 163 additional
characters preserve the exact heartbeat target, one attempt, verified stopping,
unconfirmed-result handling and prohibition on work/spend/retry fallback. The
brief presentation allowance becomes 4,600, leaving 153 characters of headroom.
The two original scope paragraphs and current-Turn settlement instructions stay
intact. This is a regression-budget adjustment, not a model context limit or an
execution allowance; all other mode limits, field counts, quota and authority
remain unchanged. The original 4,300-character failure is retained in validation.

同一 Codex App brief 双范围 fixture 在 v1.4.1 为 4,284 个归一化正文字符,加入共享停止/
读回规则后为 4,447,增加 163;保留准确停止对象、单次尝试、停止验证、未确认结果处理
以及禁止 work/spend/retry fallback。brief 展示预算调至 4,600,保留 153 字符余量,
不删除两段原范围与当前 Turn 结算规则。其余模式、字段数、执行配额和权限不变;
原 4,300 上限失败保留,不能将新展示预算称为模型上下文或执行额度提升。

The earlier readable-peer qualification raised the thin body ceiling from 2,500
to 3,000; those historical measurements follow.
On the same real CLI fixture with a host scope and three runtime capabilities,
Expand Down
3 changes: 2 additions & 1 deletion examples/blocker-push-runtime-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ def main() -> int:
# The bootstrap rule is shared from heartbeat.rules after #4201; assert the
# current compact sentence instead of the retired per-shell phrasing.
assert "reuse the value on retries" in compact_prompt, prompt
assert "guard; 2 stalls->replan" in compact_prompt, prompt
assert "re-enter guard." in compact_prompt, prompt
assert "2 stalls->replan" not in compact_prompt, prompt
assert "Exact monitor settlement=no refresh/spend" in compact_prompt, prompt
assert "Admitted work: settlement_plan even if artifacts unchanged" in compact_prompt, prompt
# The shipped writeback sentence moved to the mixed-language form in the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
CANARY_TODO_ID = "todo_integrated_canary"
CANARY_TODO_TITLE = "Design bounded status/quota/review-packet/Todo/read-path canary"
SUCCESSOR_TODO_TITLE = "Continue integrated Markdown successor routing canary"
MARKDOWN_CONTINUATION_TITLE = "Continue same-agent markdown continuation through status and quota."
MARKDOWN_CONTINUATION_TITLE = "[P1] Continue same-agent markdown continuation through status and quota."
MONITOR_TODO_ID = "todo_integrated_due_monitor"
MONITOR_TARGET_KEY = "integrated-due-monitor-watch"
VALIDATED_PROGRESS_CLASSIFICATION = "integrated_canary_validated_progress"
Expand Down
2 changes: 1 addition & 1 deletion examples/control_plane/quota-no-git-status-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def main() -> int:
)
assert quota.get("status") != "quota_collection_failed", quota
assert quota["should_run"] is True, quota
assert quota["recommended_action"] == "Solve the no-git quota fixture.", quota
assert quota["recommended_action"] == "[P1] Solve the no-git quota fixture.", quota
return 0


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,11 @@ def assert_status_read_path(
runtime_root=runtime_root,
)
item = status_item(payload)
assert item["status"] == POST_HANDOFF_CLASSIFICATION, item
assert item["status"] == "active_state_agent_todo", item
assert item["source"] == "active_state", item
assert item.get("stale_latest_run_warning") is None, item
assert item["waiting_on"] == "codex", item
assert item["recommended_action"] == POST_HANDOFF_ACTION, item
assert item["recommended_action"] == f"[P1] {TODO_TITLE}", item
assert item["project_asset"]["active_state_next_action"] == GOAL_NEXT_ACTION, item
assert item["project_asset"]["latest_validation"]["classification"] == POST_HANDOFF_CLASSIFICATION, item
assert item["project_asset"]["latest_validation"]["summary"] == POST_HANDOFF_ACTION, item
Expand Down
16 changes: 8 additions & 8 deletions examples/control_plane/todo-cli-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@


GOAL_ID = "todo-cli-goal"
USER_TODO = "Review the owner decision checklist before approving delivery."
SCOPED_USER_GATE = "Choose the side-agent publishing channel before posting externally."
AGENT_TODO = "Summarize the read-only evidence after the user checklist is done."
USER_TODO = "[P1] Review the owner decision checklist before approving delivery."
SCOPED_USER_GATE = "[P1] Choose the side-agent publishing channel before posting externally."
AGENT_TODO = "[P1] Summarize the read-only evidence after the user checklist is done."
AGENT_TODO_NOTE = "Start from the public-safe evidence summary."
UPDATED_AGENT_TODO_NOTE = "Preserve the validated summary as the handoff context."
UPDATED_AGENT_TODO = "Publish the compact evidence summary after validation passes."
MONITOR_TODO = "Monitor the release-note draft PR until the next scheduled check."
UPDATED_AGENT_TODO = "[P1] Publish the compact evidence summary after validation passes."
MONITOR_TODO = "[P1] Monitor the release-note draft PR until the next scheduled check."
MONITOR_DUE_AT = "2026-01-02T00:00:00+00:00"
MONITOR_NEXT_DUE_AT = "2026-01-03T00:00:00+00:00"
MONITOR_EXPIRES_AT = "2026-01-04T00:00:00+00:00"
Expand Down Expand Up @@ -299,7 +299,7 @@ def main() -> int:
assert "has no coordination.registered_agents" in legacy_claim["error"], legacy_claim
assert "Register this peer identity first" in legacy_claim["error"], legacy_claim
assert "--registered-agent codex-main-control" in legacy_claim["error"], legacy_claim
wrapped_agent_todo = "- [ ] Summarize the read-only evidence after the user\n checklist is done."
wrapped_agent_todo = "- [ ] [P1] Summarize the read-only evidence after the user\n checklist is done."
state_file.write_text(
state_file.read_text(encoding="utf-8").replace(f"- [ ] {AGENT_TODO}", wrapped_agent_todo),
encoding="utf-8",
Expand Down Expand Up @@ -351,8 +351,8 @@ def main() -> int:
}
], metadata_payload
after_metadata = state_file.read_text(encoding="utf-8")
assert after_metadata.count("- [ ] Summarize the read-only evidence after the user") == 1, after_metadata
agent_block_start = after_metadata.index("- [ ] Summarize the read-only evidence after the user")
assert after_metadata.count("- [ ] [P1] Summarize the read-only evidence after the user") == 1, after_metadata
agent_block_start = after_metadata.index("- [ ] [P1] Summarize the read-only evidence after the user")
agent_metadata_start = after_metadata.index("<!-- loopx:todo", agent_block_start)
assert after_metadata.index("checklist is done.", agent_block_start) < agent_metadata_start, after_metadata
assert "status=open task_class=advancement_task action_kind=run_eval" in after_metadata
Expand Down
4 changes: 2 additions & 2 deletions examples/control_plane/todo-concurrent-write-lock-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@


GOAL_ID = "todo-concurrent-write-lock-goal"
CHILD_ADD_TODO = "Child add should preserve the parent todo written under lock."
CHILD_ADD_TODO = "[P1] Child add should preserve the parent todo written under lock."
PARENT_ADD_TODO = "Parent todo written while child add waits on the lock."
UPDATE_TARGET_TODO = "Update target todo should keep unrelated concurrent additions."
UPDATE_TARGET_TODO = "[P1] Update target todo should keep unrelated concurrent additions."
PARENT_UPDATE_TODO = "Parent todo written while child update waits on the lock."


Expand Down
8 changes: 4 additions & 4 deletions examples/control_plane/todo-lifecycle-cli-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,11 +286,11 @@ def assert_nonblocking_review_continuation() -> None:
"--evidence",
"feature PR is validated and ready for review",
"--next-user-todo",
"Review the validated experiment feature PR.",
"[P1] Review the validated experiment feature PR.",
"--next-user-task-class",
"user_action",
"--next-agent-todo",
"Continue the next independent experiment feature.",
"[P1] Continue the next independent experiment feature.",
"--next-claimed-by",
"codex-main-control",
"--next-action-kind",
Expand All @@ -301,7 +301,7 @@ def assert_nonblocking_review_continuation() -> None:
review = next(
item
for item in fields["user_todos"]["items"]
if item["text"] == "Review the validated experiment feature PR."
if item["text"] == "[P1] Review the validated experiment feature PR."
)
assert review["task_class"] == "user_action", review
assert review["bound_agent"] == "codex-main-control", review
Expand All @@ -311,7 +311,7 @@ def assert_nonblocking_review_continuation() -> None:
continuation = next(
item
for item in fields["agent_todos"]["items"]
if item["text"] == "Continue the next independent experiment feature."
if item["text"] == "[P1] Continue the next independent experiment feature."
)
assert continuation["status"] == "open", continuation
assert continuation["claimed_by"] == "codex-main-control", continuation
Expand Down
3 changes: 2 additions & 1 deletion examples/install-local-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,8 @@ def main() -> int:
)
assert "```sh\nLOOPX_TURN=<current_time_iso>\n" in payload["task_body"], payload
assert "not a command-prefix assignment" in payload["task_body"], payload
assert "guard; 2 stalls->replan" in payload["task_body"], payload
assert "re-enter guard." in payload["task_body"], payload
assert "2 stalls->replan" not in payload["task_body"], payload
assert "Exact monitor settlement=no refresh/spend" in payload["task_body"], payload
assert "Admitted work: settlement_plan even if artifacts unchanged" in payload["task_body"], payload
assert "no-change=surface_only/no spend" not in payload["task_body"], payload
Expand Down
6 changes: 3 additions & 3 deletions examples/project/global-manager-command-cli-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,9 @@ def assert_risks_payload(payload: dict[str, object]) -> None:
], payload

stale_rows = payload["groups"]["stale_runs"]
assert stale_rows, payload
assert stale_rows[0]["kind"] == "stale_latest_run_projection", stale_rows
assert stale_rows[0]["goal_id"] == GOAL_ID, stale_rows
# Current Todo reads reconcile this ordinary stale progress projection.
# Historical failures and unavailable sources retain their independent risks.
assert stale_rows == [], payload
assert any(
warning["reason_code"] == "global_registry_unavailable"
for warning in payload["source_warnings"]
Expand Down
2 changes: 1 addition & 1 deletion examples/project/project-agent-adoption-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

REPO_ROOT = Path(__file__).resolve().parents[2]
GOAL_ID = "adoption-main-control"
USER_TODO = "Review the P0 owner-risk checklist before approving delivery."
USER_TODO = "[P1] Review the P0 owner-risk checklist before approving delivery."
AGENT_TODO = "Run the read-only map dry-run after the operator approval is recorded."
APPROVED_COMMAND = f"loopx read-only-map --goal-id {GOAL_ID} --dry-run"
QUOTA_EXECUTION_CONTEXT = (
Expand Down
2 changes: 1 addition & 1 deletion loopx/control_plane/collaboration/operation_wake.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def dispatch_confirmed_operation_wake(
if parameters["goal_id"] != configuration["goal_id"]:
return {**base, "state": "out_of_scope"}
config_path = _configuration_path(Path(configuration["project"]), configuration["execution_config"])
raw_config = json.loads(config_path.read_text())
raw_config = json.loads(config_path.read_text(encoding="utf-8"))
if raw_config.get("schema_version") != "loopx_local_delegation_v0":
raise ValueError("unsupported operation launch configuration")
bindings = raw_config.get("bindings")
Expand Down
2 changes: 1 addition & 1 deletion loopx/control_plane/heartbeat/budget.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
INTERFACE_BUDGET_CHARS = {
"full": 12_000,
"compact": 6_700,
"brief": 4_300,
"brief": 4_600,
"thin": 3_200,
"visible_goal": 4_000,
}
Expand Down
2 changes: 1 addition & 1 deletion loopx/control_plane/turn_driver/dsh_operation_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def _sdk_runtime_pin(runtime_bin: Path | None = None) -> dict[str, Any]:
if runtime_bin is not None:
entry = runtime_bin.resolve(strict=True)
package = entry.parent.parent
manifest = json.loads((package / "package.json").read_text())
manifest = json.loads((package / "package.json").read_text(encoding="utf-8"))
modules = package.parent.parent
if (
sdk.version != "0.2.1a3"
Expand Down
4 changes: 2 additions & 2 deletions loopx/presentation/codex_attached_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def _codex_attached_read(self) -> None:
"No delivery receipt is recorded for this input.", status=404
)
return
receipt = json.loads(receipt_path.read_text())
receipt = json.loads(receipt_path.read_text(encoding="utf-8"))
if receipt.get("binding_ref") != binding["binding_ref"]:
raise ValueError("Delivery belongs to an older binding")
http._send_json(receipt_readback(receipt))
Expand Down Expand Up @@ -300,7 +300,7 @@ def _codex_attached_send(self) -> None:
fingerprint = input_fingerprint(body["binding_ref"], body["text"])
with exclusive_file_lock(path):
if path.exists():
receipt = json.loads(path.read_text())
receipt = json.loads(path.read_text(encoding="utf-8"))
if receipt["fingerprint"] != fingerprint:
raise ValueError("Operation id belongs to a different input")
http._send_json(receipt_readback(receipt))
Expand Down
14 changes: 7 additions & 7 deletions tests/architecture/test_control_plane_import_boundaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def _module_name(path: Path) -> str:
def _resolved_imports(path: Path) -> set[str]:
module_name = _module_name(path)
package_name = module_name if path.name == "__init__.py" else module_name.rpartition(".")[0]
tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
tree = ast.parse(path.read_bytes(), filename=str(path))
imports: set[str] = set()
for node in ast.walk(tree):
if isinstance(node, ast.Import):
Expand All @@ -92,7 +92,7 @@ def _resolved_from_imports(path: Path) -> dict[str, set[str]]:
if path.is_relative_to(PACKAGE_ROOT):
module_name = _module_name(path)
package_name = module_name if path.name == "__init__.py" else module_name.rpartition(".")[0]
tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
tree = ast.parse(path.read_bytes(), filename=str(path))
imports: dict[str, set[str]] = {}
for node in ast.walk(tree):
if not isinstance(node, ast.ImportFrom):
Expand All @@ -107,7 +107,7 @@ def _resolved_from_imports(path: Path) -> dict[str, set[str]]:


def _top_level_imported_names(path: Path) -> set[str]:
tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
tree = ast.parse(path.read_bytes(), filename=str(path))
return {
alias.asname or alias.name
for node in tree.body
Expand All @@ -117,7 +117,7 @@ def _top_level_imported_names(path: Path) -> set[str]:


def _top_level_function_names(path: Path) -> set[str]:
tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
tree = ast.parse(path.read_bytes(), filename=str(path))
return {
node.name
for node in tree.body
Expand All @@ -128,7 +128,7 @@ def _top_level_function_names(path: Path) -> set[str]:
def _top_level_import_bindings(path: Path) -> dict[str, str]:
module_name = _module_name(path)
package_name = module_name.rpartition(".")[0]
tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
tree = ast.parse(path.read_bytes(), filename=str(path))
bindings: dict[str, str] = {}
for node in tree.body:
if isinstance(node, ast.Import):
Expand All @@ -144,7 +144,7 @@ def _top_level_import_bindings(path: Path) -> dict[str, str]:


def _public_import_only_bindings(path: Path) -> dict[str, str]:
tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
tree = ast.parse(path.read_bytes(), filename=str(path))
loaded_names = {
node.id
for node in ast.walk(tree)
Expand All @@ -161,7 +161,7 @@ def _public_contract_evidence() -> dict[tuple[str, str], set[str]]:
evidence: dict[tuple[str, str], set[str]] = {}
for root in PUBLIC_CONTRACT_ROOTS:
for path in root.rglob("*.py"):
tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
tree = ast.parse(path.read_bytes(), filename=str(path))
# Aliases such as ``from loopx import status as status_module`` are a
# real consumer of a facade export, reached by attribute access
# rather than a from-import. Without this map the audit would report
Expand Down
Loading
Loading