Skip to content

[WIP]feat(miniapp): add built-in bitfun-loopx console MiniApp (replaces #2382) - #2836

Open
xielixing wants to merge 18 commits into
GCWing:mainfrom
xielixing:builtin/loopx-miniapp
Open

[WIP]feat(miniapp): add built-in bitfun-loopx console MiniApp (replaces #2382)#2836
xielixing wants to merge 18 commits into
GCWing:mainfrom
xielixing:builtin/loopx-miniapp

Conversation

@xielixing

Copy link
Copy Markdown

Summary

Replaces #2382 (closed when main was replaced with the 1.0.0 codebase). This PR reapplies the built-in bitfun-loopx console MiniApp on the new main and links back to #2382 for review context.

内置 MiniApp bitfun-loopx(品牌统一为 bitfun-loopx,src/crates/contracts/product-domains/src/miniapp/builtin/assets/bitfun-loopx/ 即权威源码,不依赖任何外部仓库快照):粘贴 GitHub Issue 链接,由 OpenBitFun 宿主 Agent 驱动本机 loopx 持续修复,心跳调度、人工审批、中途插话。

Ported from #2382 (adapted to the 1.0.0 codebase)

  1. 内置 miniapp: assets committed under product-domains/src/miniapp/builtin/assets/bitfun-loopx/; registered in BUILTIN_APPS (builtin.rs) with the content-hash seed policy of the 1.0.0 codebase; private_bridge_extension exposes app.loopx.* only to the verified built-in identity (builtin-bitfun-loopx).
  2. Rust contracts: product-domains/src/miniapp/loopx/{types,ports,policy,bridge}.rs — typed DTOs, narrow ports, pure lifecycle policy (cargo test -p openbitfun-product-domains --features miniapp covered by loopx_contracts).
  3. Services: services-integrations/src/miniapp/loopx_{cli,github,workspace}.rs behind the new miniapp-loopx feature — pinned sidecar selection + typed CLI argv/JSON translation + durable readback, GitHub intake adapter, Git/worktree service.
  4. Assembly/core: core/src/miniapp/loopx/{controller,agent_adapter,store,subscriber,tool_activity}.rs — host driver, batch/queue, fair rotation, recovery and state projection; custom-agent-runner path per the LoopX mainstream cooperative runner contract.
  5. Desktop: miniapp_loopx_api.rs (7 Tauri commands, registered in lib.rs, declared in the Product Operation Registry with Unsupported/ControllerLocal stances), bundled loopx sidecar resolution (BITFUN_RESOURCE_DIR), worker_host.js policy/environment handling.
  6. Packaging: scripts/build-loopx.mjs (pinned loopx v0.5.1 @ 1bb42f4c, PyInstaller onefile) invoked by scripts/desktop-tauri-build.mjs (prepareBundledLoopx + injectLoopxResource, --no-bundle skip) and scripts/dev.cjs (ensureLoopxSidecar); CI (desktop-package.yml / nightly-artifacts.yml) installs Python 3.13; THIRD_PARTY_NOTICES.md carries the LoopX MIT/NOTICE/TRADEMARKS obligations; resources/loopx/ is gitignored (generated artifact).
  7. Web UI: LoopxAPI.ts, loopxBridgeProtocol.ts, MiniApp scene/bridge updates, FlowChat/event wiring, locales (zh-CN/zh-TW/en-US).
  8. Docs: asset AGENTS.md/README.md updated to OpenBitFun naming; desktop AGENTS.md reconciled with the registry-driven peer/workspace policy.

Deviations / notes

  • BitFun-Installer lockfile commit from feat(miniapp): add builtin bitfun-loopx console MiniApp #2382 is dropped: the 1.0.0 repo pins generated installer lockfiles out of git (.gitignore, OpenBitFun-Installer).
  • Peer/workspace stances now live in remote_surface/table.rs (Product Operation Registry) instead of the removed hand-written tables; loopx commands are Unsupported on remote workspaces, ControllerLocal under Peer Device Mode (contracts to be negotiated across peers), CLI peer host refuses before dispatch.
  • LoopX CLI pin: v0.5.1 @ 1bb42f4c (same as feat(miniapp): add builtin bitfun-loopx console MiniApp #2382's later state).
  • Verification on the new codebase: cargo check -p openbitfun-product-domains --features miniapp, cargo check -p openbitfun-services-integrations --no-default-features --features miniapp-runtime,miniapp-loopx, plus the desktop/core compile chain (see checklist).

Fixes # (none; replaces the closed #2382)

Type and Areas

Type: Feature

Areas: contracts/product-domains (builtin MiniApp assets, loopx contracts), services-integrations (loopx CLI/GitHub/workspace adapters), assembly/core (LoopX controller), Desktop (Tauri commands, sidecar bundling), Web UI, scripts/CI, docs, THIRD_PARTY_NOTICES

Motivation / Impact

loopx (huangruiteng/loopx) is a control plane CLI for long-running Agent tasks: goals, todos, gates, quotas are all recorded, but it has no scheduler or executor. bitfun-loopx adds both: a heartbeat alarm and the OpenBitFun host Agent as the hand. Marketplace installs are limited by the marketStrict runtime tier and cannot run the repair loop; the built-in version is not.

The bundled sidecar means users need neither Python, git, nor network access to use loopx; the MIT redistribution obligations ship alongside the binary (LICENSE / NOTICE / LICENSE-MIT / TRADEMARKS / manifest.json in resources/loopx/, plus THIRD_PARTY_NOTICES.md).

Verification

  • cargo check -p openbitfun-product-domains --features miniapp — passes (loopx_contracts + builtin_miniapp covered)
  • cargo check -p openbitfun-services-integrations --no-default-features --features miniapp-runtime,miniapp-loopx — passes
  • node --test scripts/desktop-tauri-build.test.mjs — 17/17
  • node scripts/check-core-boundaries.test.mjs — loopx feature-ownership rules included (see the env-artifact note during migration)
  • (list the final desktop/core check results once the chain completes)

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

Replaces GCWing#2382, which was closed when main was replaced with the 1.0.0
codebase; this branch is based on the new main and reapplies the built-in
LoopX console MiniApp for OpenBitFun.

Highlights:
- Built-in MiniApp assets (product-domains/src/miniapp/builtin/assets/bitfun-loopx)
  registered via BUILTIN_APPS with the content-hash seed policy; private
  app.loopx.* bridge is injected only for the verified built-in identity
  (builtin-bitfun-loopx).
- LoopX contracts (types/ports/policy/bridge) in product-domains; pinned
  sidecar CLI adapter + GitHub intake + worktree service behind the new
  services-integrations 'miniapp-loopx' feature.
- Core LoopX controller, agent adapter, store, subscriber, tool activity in
  assembly/core (custom-agent-runner path per the LoopX cooperative runner
  contract); desktop Tauri surface (7 commands) with Product Operation
  Registry rows (Unsupported / ControllerLocal / REFUSED).
- Bundled loopx sidecar build pipeline: scripts/build-loopx.mjs (pinned
  v0.5.1 @ 1bb42f4c) wired into desktop-tauri-build.mjs and dev.cjs,
  Python 3.13 in the packaging CI, THIRD_PARTY_NOTICES obligations.
- Web UI: LoopxAPI/loopxBridgeProtocol, bridge + flow-chat wiring, locales.
- Dropped the closed-PR installer-lockfile commit: the 1.0.0 repo pins
  generated installer lockfiles out of git (OpenBitFun-Installer policy).

Verified: cargo check -p openbitfun-product-domains --features miniapp;
cargo check -p openbitfun-services-integrations with
miniapp-runtime,miniapp-loopx,web-tools; cargo check -p openbitfun-core
--features product-full; cargo check -p openbitfun-desktop;
cargo test -p openbitfun-product-domains remote_surface (19/19);
pnpm run capabilities:generate; pnpm --dir src/web-ui run gen:types;
pnpm run type-check:web; node --test scripts/desktop-tauri-build.test.mjs.
@xielixing

Copy link
Copy Markdown
Author

Replaces closed PR #2382 (feat(miniapp): add builtin bitfun-loopx console MiniApp) — same work reapplied on the current \main, per the migration note on #2382. See #2382 for the original review context.

@xielixing xielixing changed the title feat(miniapp): add built-in bitfun-loopx console MiniApp (replaces #2382) [WIP]feat(miniapp): add built-in bitfun-loopx console MiniApp (replaces #2382) Sep 6, 2026
xielixing and others added 12 commits September 7, 2026 00:09
…fy approval copy

- loopx_cli.rs: decode sidecar stdout/stderr/payload as strict UTF-8 first, then GBK (the PyInstaller bundle ignores PYTHONUTF8 and always emits the ANSI code page, so lossy UTF-8 decode turned Chinese gate messages into U+FFFD mojibake); keep PYTHONUTF8/PYTHONIOENCODING for the managed-source Python entrypoint; add encoding_rs behind the miniapp-loopx feature

- ui.js/index.html: open the raw request by default; rewrite approve/reject/recommendation copy to name the concrete boundary (writes/commits, builds, installs, real-run validation) and why approval is needed; stop duplicating the request text in the decision card
Bundle of adapter-level fixes driven by a live A/B against the loopx
0.5.1 + codex reference run (same three fixture issues on both hosts):

- CLI adapter: inject --runtime-root <worktree>/.loopx/runtime on every
  loopx invocation; bootstrap passes --state-file into .loopx/goals and
  (after bootstrap) patches the registry common_runtime_root to the
  project-local runtime plus re-points legacy state_file away from
  .codex paths, so the worktree stays fully .loopx-namespaced and never
  touches the shared ~/.codex/loopx global registry.
- Turn instruction: append the pinned CLI reference and the verbatim
  pinned workflow-skill documents (loopx-project + loopx-self-repair
  SKILL.md) on the FIRST turn of each agent session only (codex-style
  session-start skill load; later turns carry a short pointer so prompt
  cache and per-turn cost stay low). Closing-ceremony note carries the
  exact required no_followup flag set and vision contract requirements.
- shell_analysis: accept powershell/pwsh/cmd dialects with hard input
  limits so the complete-shell guard stops failing closed on every
  Windows ExecCommand (whoami included).
- MiniApp UI: preserve the technical-receipt <details> open state
  across re-renders (was collapsing on every snapshot attach);
  suite-level pause_all/resume_all allowed by the web-ui bridge guard.
- build-loopx: bundle loopx skills via --add-data so the frozen sidecar
  ships the workflow-skill data (verified workflow-skills --install).
- AGENTS.md: record the codex-comparison methodology and the root-cause
  facts (runtime root localization, required closure flags, dialect
  guard) for future maintainers.
- Seed the pinned LoopX reference (CLI help reference + verbatim official
  workflow-skill documents) into .loopx/pinned-loopx-reference.md when the
  workspace connects; the turn instruction now only carries a short pointer
  (read once per session, reuse from context) instead of pasting ~130KB into
  every instruction - mirrors how a LoopX codex-style host loads its workflow
  skills, and keeps per-turn prompts cache-friendly.
- Slim LOOPX_CLOSING_CEREMONY_NOTE to host facts only: follow the reference
  document for schemas/flags; typed refusal -> apply the named parameter once,
  blocker after two ordered attempts; runtime stays project-local. The previous
  hand-written flag listing duplicated the docs and the 'minimal evidence'
  guidance caused repository_context=not_provided drift, so both were removed.
… terminal UX

Three live A/B runs against the loopx 0.5.1 + codex reference (same three
fixture issues) drove this batch; every fix cites its observed failure.

Execution parity (issue 1 went 16.7min -> 9.8min, faster than codex):
- Re-entry instructions now carry copy-ready settlement commands mirroring
  the pinned v0.5.1 canonical templates (effect_program.py writeback,
  autonomous_replan_obligation.py replan ACK with accountable
  delivery-outcome): the outer-controller envelope only ships a bare
  template, and agents re-derived flags from help text into 42 typed
  refusals ("turn-scoped refresh-state requires an accountable
  --delivery-outcome"; surface_only is not accountable).
- The replan ACK guidance embeds the exact goal_vision_replan_contract_v0
  packet shape with enforced budgets - the agent's own blocker todo asked
  the host to document this schema.
- Agent sessions now continue across turns of one goal (codex exec resume
  parity): settlement keeps the session for Queued/WaitingForUser turns,
  discards it on terminal/failure, and stale ids fall back to fresh
  sessions. Continued turns get an "already loaded" reference pointer
  (read policy has a single source: exactly one Read directive on the
  first turn, zero afterwards).
- agent-onboard pack is fetched after register-agent so it carries the
  registered agent id; monitor-recheck clock skew clamps at zero.

Owner-gated publishes (A9):
- Environment boundary now forbids git push / gh pr create / gh issue
  comment / gh pr merge unless the turn contract explicitly carries the
  approval, mirroring loopx requires_user_gate_before_external_write; a
  todo's text ("open a PR") is a plan description, not an authorization.
  Verified: 0 push/PR executions in the follow-up run (previously a PR
  was opened without approval).

Truthful projections (A7/A8):
- A user wait without a typed user_gate (e.g. the owner review/merge
  queue entry recorded after a PR) now projects as an owner-action
  summary and parks the task as waiting instead of failing the whole
  inspection and marking finished work recovery_required.
- The replan-lineage salvage accepts every typed envelope the pinned CLI
  still prints under that contract error (live settlement previously
  failed on an open blocker todo) and projects RunNow/Complete/Wait from
  the envelope shape.

Terminal UX:
- Completed goals render a plain-language outcome note (GitHub activity
  does not restart a finished goal) instead of the agent's control-plane
  next-step wording; verdict badges show the concrete reason (wont-fix
  rationale, missing info) instead of a repeated static note; the
  rejected-options block is gone; an empty issue body no longer renders
  as an endless "loading" placeholder.
- Agents must keep control-plane vocabulary out of human-facing summary
  fields, and a terminal-rejected quota spend is not a blocker (the goal
  is simply closed); completed tasks no longer render a blockers card.
- GitHub data must go through the gh CLI (direct WebFetch gets 403).

LoopX knowledge stays pinned: all embedded shapes (delivery outcomes,
vision contract, closeout flags) cite the pinned v0.5.1 validation code
by file and are regenerated when LOOPX_PINNED_VERSION moves. See the
bitfun-loopx AGENTS.md for the full run evidence and methodology.
LoopX v1.0.x moved the control-plane core (coordination state, turn
envelopes, vision checkpoints) to a managed TypeScript effect runtime the
Python sidecar starts on demand via `node --experimental-strip-types`.
Verified live against a clean v1.0.1 checkout: bootstrap fails closed with
"LoopX Effect runtime requires Node.js 22.6.0 or newer" when Node is
absent, so the upgrade ships a Node dependency surface instead of bundling
Node (installer size).

Runtime compatibility (each verified against the v1.0.1 source and the
rebuilt frozen sidecar, full chain bootstrap -> register-agent -> todo ->
turn plan -> guard -> refresh-state -> spend -> complete -> history):
- Every BitFun argv builder stays compatible; register-agent's new shape
  (no --project, global-registry write behind --execute) is exactly what
  BitFun already passes.
- All schemas BitFun parses are unchanged (turn_plan/envelope v0, workflow
  plan packet v0, settlement identity v0+v1, vision contract v0, progress
  observation v0, command reference v0).
- The turn-scoped refresh-state refusal was reworded but stays semantically
  equal (outcome_progress still qualifies); lineage error text, vision
  budgets, terminal-no-followup semantics, envelope budget all identical.
- Skills content: only loopx-self-repair and loopx-pr-review changed;
  pinned resources regenerated wholesale from v1.0.1 (CLI help reference
  recaptured across all eight commands).

Changes:
- Pin constants -> 1.0.1 / v1.0.1 / 7f2a020b (adapter, contracts, tests).
- build-loopx.mjs: stage the control-plane .ts/.json runtime sources as
  PyInstaller data (subset staging keeps .py modules out of the data area
  where loose sources could shadow frozen modules); compliance files now
  follow what the checkout carries (v1.0.1 dropped TRADEMARKS.md).
- Handshake now probes Node (>= 22.6, matching loopx's own floor) and
  returns it as LoopxNodeRuntimeFact on the manifest; the environment
  surface gains a core "Node.js" fact that blocks with an install hint
  when missing. Hermetic tests disable the probe via config.
- build_turn recognizes the guard's typed `turn_envelope_skipped`
  degradation (upstream #3687) and fails loudly with the skip reason
  instead of a generic missing-signature error.
Update the codex comparison baselines and reproduction manual in the
bitfun-loopx AGENTS.md with data from the 2026-09-08 v1.0.1 codex run:

- v1.0.1 baseline: issue #2 real fix 7m37s / 204K tokens / 58 execs,
  exact README +2 lines, stopped at owner gate, zero external writes.
  BitFun same issue 9.1 min - gap is ~1.5 min from per-turn host
  scheduling (inspect -> build -> settle), not agent execution.
- Corrected methodology: exec injection is not the official codex path
  (official goes TUI + skill discovery + heartbeat loop) but remains
  valid as comparison data since the guided packet structure drives
  the complete issue-fix loop.
- Documented sandbox pitfall: `--sandbox workspace-write` fails on
  Windows with `CreateProcessAsUserW failed: 5`; use
  `danger-full-access` with explicit operator safety boundaries.
- Documented v1.0.1 requirements for the lab: Node.js >= 22.6 on PATH
  (TS control plane), .cmd suffix needed for codex exec on Windows.
- Issue #1 no-op comparison incomplete (codex exec hung after
  register-agent for 17 min); noted for rerun.
Full v1.0.1 codex comparison run (deepseek-v4-flash, exec injection,
danger-full-access sandbox):
- #1 no-op: 7m00s / 202K tokens / 135 execs, terminal_no_followup,
  zero changes
- #2 real fix: 7m37s / 204K tokens / 58 execs, exact README +2 lines,
  stopped at owner gate, zero external writes
- #3 acknowledgment: 10m37s / 234K tokens / 114 execs,
  triage_only/no_followup, zero changes

All three closed cleanly with GitHub untouched. BitFun same-day numbers:
9.8 / 9.1 / 10.5 min - total gap ~4 min across the suite, attributable
to per-turn host scheduling (inspect -> build -> settle 30-60s each),
not agent execution differences.
The 9.8/9.1/10.5 min BitFun numbers in the comparison table came from
the v0.5.1 + codex-parity-fix run, not from the v1.0.1 upgrade. The
v1.0.1 BitFun verification has not run yet; correct the table until
real v1.0.1 numbers are collected.
Four root causes verified against the pinned CLI with live goals; each
fix removes the patches that were compensating for it.

1. Settlement binding must follow the loopx receipt authority chain
   (live 2026-09-09: issue-2's turn-2 writeback AND quota spend were
   correctly recorded todo-bound on the server, but the host expected
   the autonomous_replan effect id and settled every such turn as
   NoDurableProgress). `planned_settlement_binding` now mirrors
   `quota_rollout_settlement_binding`: the typed
   `writeback.replan_settlement_contract` wins, then the selected todo,
   and only a todo-less frontier settles through the obligation. The
   writeback command flavor follows the SEMANTIC obligation instead
   (todo_bound_writeback: the obligation shapes the flags while the
   settlement records through the todo).

2. Continuation inspections probe the live quota decision
   (`quota should-run --turn-envelope`, no turn identity) instead of
   `turn plan` - codex/pi host parity. `turn plan` has an 8192-byte
   envelope-budget gate that degrades to contract_error and strands
   the goal (live: 9078-byte envelope); the quota decision keeps
   projecting should_run/selected todo past it. The probe never mints
   a heartbeat receipt. `envelope_over_budget` stays informational.

3. Two-phase action selection (live: the frontier held two eligible
   candidates, the guard refused a settlement identity and withheld
   the writeback commands). build_turn now binds the envelope's
   recommended todo via a `--todo-id` re-run carrying the SAME turn
   identity, then re-reads the bound contract. Verified as a three-
   step protocol against the pinned binary.

4. User-gated frontier parking (live: issue-3 reached an owner-decision
   frontier; the envelope projected should_run=true through the
   agent_with_user_gate fallback with no agent work item, and the
   strict no-binding check failed the task into recovery). The
   controller now parks such frontiers as WaitingForUser via the
   extracted `waiting_user_frontier` helper instead of driving a model
   turn that cannot settle; the UI already surfaces the gate.

Removed with the root causes: the turn-plan over-budget degradation
and replan-lineage salvage machinery, the legacy receipt path, the
v0.5.1 monitor compat cadence and the always-empty scheduler_hint_ms
readers, the host-side registry JSON surgery (bootstrap localizes
common_runtime_root natively from the injected --runtime-root), and
the hardcoded v0.5.1 install copy in the MiniApp UI (now filled from
the environment fact).

Also: managed-source dir derives from LOOPX_PINNED_VERSION_TAG, the
MiniApp thin-client tests are fixed (8/8; the 8cf71c7 approval-copy
rewrite never updated them), and the branch's loopx_contracts test
target compiles again.

Verified live: issue-3 on the fixed build settled 4/4 turns cleanly
in ~9.2 min (codex baseline 10.6 min), reaching the owner gate
without a single NoDurableProgress.
# Conflicts:
#	docs/interactive-capabilities/README.md
#	docs/interactive-capabilities/technical/tauri-command-map.json
#	scripts/check-core-boundaries.test.mjs
#	scripts/core-boundaries/cargo-dependency-boundaries.mjs
#	scripts/core-boundaries/explicit-test-topology.mjs
#	scripts/core-boundaries/rules/feature-rules.mjs
#	scripts/desktop-tauri-build.mjs
#	scripts/dev.cjs
#	src/crates/assembly/core/src/service/config/types.rs
#	src/crates/assembly/core/src/service/session_projection_store.rs
#	src/crates/contracts/product-domains/Cargo.toml
#	src/crates/contracts/product-domains/src/generated/remote-surface-registry.json
#	src/crates/contracts/product-domains/src/remote_surface/table.rs
#	src/crates/services/services-integrations/Cargo.toml
#	src/web-ui/src/infrastructure/api/generated/remoteSurface.ts
…sume_all

The LoopX controller dispatches both actions (miniapp/loopx/controller.rs
pause_all/resume_all) and loopxBridgeProtocol.ts already lists them, but the
LoopxActionKind union omitted them, so tsc failed with TS2769 and blocked
build:web.
- config-contracts: tolerate a legacy blank custom_headers string as absent
  (Option<HashMap> with serde(default) rejected it as a type error, so the
  branch's own deserializes_empty_string_custom_headers_as_absent test failed).
- services-integrations: route the LoopX GitHub client through the crate-level
  provider-initializing reqwest_client_builder and keep reqwest::Client fully
  qualified, per the integration-module TLS rule.
- core boundaries: tools-miniapp now declares miniapp-loopx, the MiniApp
  runtime capability it already composes.
@GCWing

GCWing commented Sep 10, 2026

Copy link
Copy Markdown
Owner

beta旗舰暂不进行大特性合入,稳定性为主,后续阶段再评估

xlx1212 and others added 5 commits September 10, 2026 20:39
…ree-issue run

Live experiment (2026-09-10, deepseek-flash official, issues #1-#3) exposed
three agent-side closing failures. Fixes follow the host-fallback principle:
mechanical steps are compensated host-side, semantic inputs are pre-resolved
by the host, prompt text alone is never the last line of defense.

1. Missing quota spend receipt (issue #2 turn 4: writeback validated, spend
   skipped, task stranded in recovery with settlement_unverified).
   `verify_turn_settlement` now compensates the spend host-side using the
   exact command shape the turn instruction projected (same turn identity,
   binding flags, --source heartbeat): spend is idempotent bookkeeping, not
   a semantic claim. A terminal-closed accounting is treated as success; a
   real compensation failure still degrades loudly to RetryRequired.
   The spend instruction is also marked MANDATORY second step.

2. Vision terminal packet reworded durable fields (issue #1 turn 2: fresh
   text hit the unsatisfiable outcome=replan vs no_followup pair, burned the
   turn to NoDurableProgress). Turn instruction now embeds the recorded
   vision fields (queried via the CLI's own status projection) and demands
   character-level comparison before submit; work clause adds the
   turn-scoped settlement binding rule (a successor todo created mid-turn is
   selectable only by the NEXT turn's guard).

3. Final-response truncation decapitated the loopx_summary_v1 fence (issue
   closeout rendered as raw `\"rejected\": ...` fragments). Both bounds
   (subscriber append_bounded_text, controller bounded_agent_summary) now
   keep the TAIL where the fenced JSON contract lives.

Also:
- loopx_workspace reset retries the root rename with bounded backoff, and
  the LoopX agent cancel now waits for the turn to fully drain (the turn-id
  fast path returned after 1.5s while child processes still held handles,
  so stopping a task failed the reset with os error 5).
- New local AGENTS.md/AGENTS-CN.md for the LoopX host subsystem documenting
  the settlement contract, the host-fallback principle, and the failure
  mode -> defense table.
… to the agent

Two root causes behind the wasted turns observed in the 2026-09-10 control runs
(BitFun and a codex comparison on the same model):

1. Capability-level contracts that the official workflow skills never document
   (candidate-evidence receipts, resolution outcome enums, the
   implementation-admission decision rule) had no local source at all. The agent
   probed --help, guessed argv shapes and, on the codex side, unpacked the frozen
   PyInstaller binary and read the executable bytes for a three-value enum. The
   pinned CLI can describe that contract itself:
   `bootstrap-command-pack --capability-route issue-fix` embeds it under
   `goal_start_contract.selected_capability_route`. The host now fetches that
   read-only preview during goal creation and seeds it as
   `.loopx/capability-contracts.json`, keeping the contract version-bound to the
   pinned sidecar instead of a hand-written copy that drifts.

2. The onboarding pack advertised only `shell` while every other CLI call in the
   turn advertised the five capabilities the Agent host actually reports, so the
   agent saw two contradictory capability surfaces in one turn. Both preview
   fetches now share one helper that appends the goal context's capability list,
   with the previous `shell` fallback only when the host reports none.

Also: process_error_json uses the payload parsed when the process error was built
instead of re-parsing the captured stdout tail (that field was written but never
read); stale comments and docs describing a `turn plan` salvage path that no
longer exists are corrected; and the documentation that claimed the host may
repair a missing quota spend, that settlement is a fair rotation boundary, or
that last_agent_summary never takes part in any recovery decision now matches the
shipped behavior.

Verification: no build run (repo rule: compile only on request). Interacting
crates are services-integrations (adapter) and assembly/core (instruction
pointer + environment boundary note).
# Conflicts:
#	src/crates/contracts/product-domains/src/generated/remote-surface-registry.json
#	src/web-ui/src/infrastructure/api/generated/remoteSurface.ts
…ee-issue runs

Root-cause fixes from the 2026-09-11 live observation series on
xielixing/dynamic-workflows-lab, all structural (no error-string
matching, no case carve-outs):

1. Settlement decisions follow one rule: the authoritative Goal
   projection outranks receipts. NoDurableProgress from a completed
   turn now inspects the projection like RetryRequired, and a
   projection that reports a user gate, terminal completion, or goal
   failure skips the receipt-driven compensation turn entirely. An
   exhausted compensation episode parks for interactive recovery
   instead of requeueing into a re-drive loop.

2. Recovery reasons are distinct per failure mode
   (settlement_no_progress vs settlement_receipt_missing vs
   execution_failure) so the console copy can describe what actually
   happened instead of one misleading label.

3. The terminal close order is taught in the replan writeback
   guidance: settle the todo lifecycle (todo complete --no-follow-up)
   before the coverage-backed terminal refresh-state, verified live
   (issue #1 closed in one corrective turn once the order was known).

4. An approved gate whose frontier went empty gets its promised
   action materialized as a durable successor todo (new add_todo
   port), so approval always drives the promised work instead of
   parking plan-exhausted (live: approve -> PR GCWing#6 created in 19s).

5. A blocked publication todo (the agent's own encoding of
   'publishing needs the owner') is projected as the publish approval
   card when the plan runs dry (new list_todos / unblock_todo ports);
   approve re-opens the todo, reject remembers the decline so it
   never resurfaces.

6. Owner-action waits survive reconciliation, the waiting task can
   resume (backend accepts WaitingForUser, card carries the button
   labeled as continuation, not recovery), answered gates are never
   resurrected from history, and the resume/continue feedback is
   honest about what the action does.

7. Console presentation: approval cards carry the decision context
   (who asked for what, what the agent did, what happens next) quoted
   from the structured summary; GitHub references (PRs, issues,
   commits) link out from the narrative sections; rejected
   alternatives render from structured data instead of the truncated
   raw output.

Verified: 23/23 focused controller unit tests pass including the new
decision-rule, materialization, blocked-publication, and
reconciliation guards; the fixed binary ran three full live batches
(zero NoDurableProgress losses after the fixes, batch time down from
36 to 19 minutes).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants