Skip to content

feat(miniapp): add builtin bitfun-loopx console MiniApp - #2382

Closed
xielixing wants to merge 3510 commits into
GCWing:mainfrom
xielixing:builtin/bitfun-loopx-miniapp
Closed

feat(miniapp): add builtin bitfun-loopx console MiniApp#2382
xielixing wants to merge 3510 commits into
GCWing:mainfrom
xielixing:builtin/bitfun-loopx-miniapp

Conversation

@xielixing

@xielixing xielixing commented Aug 19, 2026

Copy link
Copy Markdown

Summary

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

本分支共 6 个提交(初始内置版 + sidecar 打包 + 后续打磨):

  1. 内置 miniappbuiltin/assets/bitfun-loopx/ 五件套 + meta + README;BUILTIN_APPS 注册 builtin-bitfun-loopx;原名 LoopX 控制台已统一品牌为 bitfun-loopx(标题、会话名、PR 标记、User-Agent);数据目录前向改名(新装 ~/.bitfun/bitfun-loopx/,旧 loopx-console 继续沿用,不搬动用户数据);探测自愈(worker 无条件把本应用 vendor 目录纳入候选)。
  2. loopx 随安装包内置(方案 A)scripts/build-loopx.mjs 构建期拉取 pin v0.2.13 源码 → venv + PyInstaller 编译单文件二进制 → 输出 LICENSE / TRADEMARKS.md / manifest.json(版本、commit、sha256、构建工具链)到 src/apps/desktop/resources/loopx/(gitignore,二进制不进仓库,每次打包构建重新拉取+编译);desktop-tauri-build.mjs 在 bundle 构建时动态注入 sidecar 资源(dev --no-bundle 跳过);desktop 解析资源目录 → 经 worker pool 以 BITFUN_RESOURCE_DIR 注入 JS worker → 内置二进制最高优先级(用户机器零 Python/git/网络),vendor/pip 兜底;CI 增加 setup-python@v5(3.13)。
  3. 移除非功能顶栏:bitfun-loopx 顶栏只放品牌名、无任何按钮,纯属浪费纵向空间,整行移除(.topbar/.brand 相关 CSS 一并清理)。
  4. gh 登录体验:流式展示登录步骤可见进度,放宽 worker 调用超时。
  5. 版本策略:内置包 version 采用按 release 提升策略(当前 1,未发布;dev 迭代靠内容哈希 reseed),新增契约测试:每个 meta.json 可解析为 MiniAppMeta、id 匹配、zh-CN/en-US i18n 完整、esm_dependencies.json 可解析;README 补充 reseed 覆盖/本地覆盖通知/storage.json 保留语义与 loopx pin 升级 runbook。
  6. 非桌面降级 + 可复现构建:MiniApp 场景在非桌面表面大声降级;BitFun-Installer 锁文件入库。

Fixes #

Type and Areas

Type: Feature

Areas: Rust core(product-domains 内置 MiniApp 资产)、MiniApp runtime、Desktop(资源解析/打包)、CI、Docs、Installer

Motivation / Impact

loopx(huangruiteng/loopx,MIT)是给长任务 Agent 记账的控制面 CLI:目标、待办、门禁、额度都记,但自己没有调度器和执行器。bitfun-loopx 补上这两样:心跳当闹钟,BitFun 宿主 Agent 当手。市场版受 marketStrict 运行时档限制跑不动修复循环,内置版不受此限。

此前 loopx 依赖运行时拉取(用户机器需要 Python 3.11+、git、网络)且探测失败率高(本机实测「未检测到 loopx CLI」)。现在构建期编译 + 安装包 sidecar 内置,打开即用;MIT 再分发义务随包履行(LICENSE/TRADEMARKS/manifest 随包 + THIRD_PARTY_NOTICES 收录)。

Verification

  • cargo test -p bitfun-product-domains --features product-full builtin_miniapp2 passed, 0 failed(id 顺序断言 + meta/deps 契约测试)
  • pnpm run check:github-config → 14/14;node --check 通过 worker.js / build-loopx.mjs / desktop-tauri-build.mjs
  • 本机端到端:pnpm run build:loopx 产出 loopx.exe(15.1 MiB,loopx v0.2.13 @ 7232dca…),--version 输出 loopx 0.2.13;应用启动日志确认 seeded builtin miniapp 'builtin-bitfun-loopx' + Resolved bundled loopx CLI resource dir: …\resources
  • 权限逐项说明:shell.allow=[loopx, python, py, git]net.allowapi.github.com / github.com;GitHub 凭据只存本机应用存储(gh CLI 或粘贴的 PAT),不写入 git config;发布 PR 必须人工批准。

Reviewer Notes

  • 合规:loopx 为 MIT(Copyright (c) 2026 LoopX contributors),二进制随包分发保留 LICENSE 与 TRADEMARKS.md;名称描述性使用,第三方集成、非官方出品;PyInstaller bootloader 有 GPL exception,产物不受 GPL 约束。
  • 构建期 vs 运行期:拉取+编译只发生在打包构建,绝不在用户机器执行;dev(--no-bundle)与内置二进制缺失时走 vendor/pip 兜底。
  • 升级纪律:loopx CLI 的 JSON 契约是本应用接口面,内置二进制 pin 与 LOOPX_VENDOR_REF 必须同步升级(当前均 v0.2.13)。
  • 生成的 src/apps/desktop/resources/loopx/.gitignore,不进仓库;macOS/Linux 的实际编译产物建议在 release/nightly 流水线观察一轮(Windows 已本机验证)。
  • 本分支在 fork(xielixing/BitFun)侧,fork 的 Actions 不自动挂到上游 PR checks,需合并侧留意。

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.

bobleer and others added 30 commits August 15, 2026 18:47
* fix(chat): make remote file mentions reliable

* fix(chat): tolerate sessions without config metadata

* fix(chat): register mention picker error state
* refactor(peer): add the device surface identity and epoch contract

Foundation for the multi-device rework: a DeviceSurfaceId that names which
device a piece of state belongs to, a monotonic activation epoch with an
AbortSignal, a typed SurfaceChangedError for unwinding stale work, and the
key-scoping helper every per-device cache must use.

Nothing consumes it yet; the layers land on top of this contract.

* refactor(peer): isolate device surface state and switching
fix(input): simplify file mention path display
Switching devices repeatedly left a session showing no live output and no
recovery: the stream stopped and nothing brought it back.

The agentic subscription is this window's only live view of a running Turn,
but its lifetime was tied to workspace bootstrap. A switch tore it down, and it
was rebuilt only as a side effect of FlowChatManager.initialize() — which a
newer switch is allowed to supersede with SurfaceChangedError, and which the
workspace effect does not re-run when both devices share a workspace path.
Nothing retried.

The attach loop was then gated on that same subscription:

    if (!agenticEventListener.getIsListening()) return;

so the one path designed to repair a missing stream refused to run precisely
when the stream was missing. Live events gone, snapshot repair disabled, frozen
until restart. AppLayout also reported the superseded bootstrap as a product
failure, hiding the cause behind a generic toast.

Make the two halves independently recoverable:

- FlowChatManager re-arms on every surface activation and retries a failed
  start on a backstop timer, so the subscription no longer depends on a
  bootstrap that may legitimately be abandoned.
- The attach loop treats a dead subscription as a reason to reconcile *and*
  re-arm it. The runtime cursor fence already covers the snapshot/live race
  while it comes back up.
- A superseded bootstrap is control flow, not a failure: no toast, and it
  ensures the subscription instead of leaving the window dark.
The Runtime already materializes an exact, cursor-ordered projection of the
executing Turn — but only in memory. Everything durable lags it: client
persistence is debounced into coalescing windows, and the persisted Session
view deliberately stores an executing Turn as idle so a restart cannot revive
work.

So the one complete record of work in flight dies with the process, and a
client returning to that Session is served a Turn frozen at the last
checkpoint. That is the gap every attach guard has been working around.

Give the journal an optional durable store: a port here, filesystem policy in
the host that owns Session storage. A materialized event persists the
projection, a terminal Turn discards it because the persisted Session view
owns the record from then on, and `snapshot` falls back to the stored
projection when memory has none.

A stored projection keeps its original stream_id, so a client correctly reads
it as a different Runtime process and replays it whole rather than comparing
cursors across processes.

No behaviour changes without a store attached; hosts are wired separately.
Makes the in-flight Turn record real-time and atomic instead of reconstructed
from a periodic summary.

The port takes one event at the moment it enters the ordered delivery stream,
not a snapshot on a timer, and the store appends it to a per-Session JSONL log
through an already-open handle. Reload replays that log through the Runtime's
own materialization, so a restored projection and a live one come from a single
implementation rather than two that can drift.

No fsync per event: an append reaches the page cache immediately, which already
survives the process crash this log exists for, and a disk flush per token
would throttle the stream it records.

Scope is deliberately the Turn in flight. The persisted Session record stays
the history of completed work — it cannot represent a running Turn because it
stores one as idle so a restart never revives work — and a terminal Turn drops
its log, so the two never describe the same thing at once.

Handles the failure modes a real log has: a torn final line after a hard kill
keeps everything already durable, and a log left by an older Runtime process is
superseded rather than replayed as current progress.
…evice

Wires the durable event log into both Hosts and removes the other way a device
could stop showing progress after repeated switching.

Desktop and CLI Peer Hosts now append the executing Turn's events to one shared
log directory. They can own the same Session at different times, so a Turn left
running by one must be replayable by the other; a Host that restarts mid-Turn
now serves the real state instead of the last client checkpoint, which the
persisted Session record stores as idle.

Separately: presence loss marks an attachment `lost` immediately, `lost` is
terminal, and `connect` refuses a lost entry. One presence blip during a burst
of switching therefore stranded a perfectly reachable device for the rest of
the session — switching to it kept failing and its sessions stayed frozen.
Presence returning now clears that dead entry so the next switch attaches a
fresh one. Keepalive-lost is deliberately untouched: presence proves
reachability, a missed ping does not.
Keep the model-visible schema strict while tolerating common malformed
CallDeferredTool payloads at runtime.

- treat missing args as an empty object
- merge top-level tool fields into args with nested values taking priority
- replay canonical tool_name and args payloads to the model
- project normalized inputs in deferred tool cards
- cover parsing, execution, replay, and UI behavior
Treat GetToolSpec as the deferred tool admission boundary instead of
requiring every invocation to pass through CallDeferredTool.

- Allow direct tool calls after loading a current catalog spec
- Preserve missing and stale spec rejection
- Keep allowlist and runtime restriction checks unchanged
- Add coverage for direct-call acceptance and pre-spec rejection
- List direct tool names alongside deferred tools in the tool-calling guide.
- Render GetToolSpec assistant results with a unified calling schema.
- Fix the deferred tool name with const and nest the original schema under args.
- Preserve the structured input_schema returned in tool result data.
- Update prompt and tool contract tests.
Remove the expandable description and input schema view from
GetToolSpecCard.

Keep the card non-interactive, trim its appearance contract, and update
coverage for compact-only rendering.
fix(desktop): disable update checks in development
Treat tent hover and one-axis half-fold separately, keep wide content
outside system Navigation, and span detail across both remaining
tri-fold screens instead of a single hinge-free band.

Co-authored-by: Cursor <cursoragent@cursor.com>
…de-layout

feat(harmonyos): keep tri-fold conversation on remaining screens
A surface switch is a view change, not a change of execution. Locally
created sessions stay at historyState new, so attach must still run, and
a turn already submitted to the host must not be re-queued or drained
while the projection is being repaired.
- Add a provider-neutral request context with a stable cache route key
- Send prompt_cache_key consistently across tool, retry, and finalize rounds
- Parse cache write token usage without conflating missing and zero values
- Add content-free request and response cache diagnostics
Capture and persist the authoritative Responses output layout,
including opaque reasoning state, for subsequent agent rounds.

- Replay reasoning, messages, and function calls in original order
- Bind replay state to the resolved model runtime fingerprint
- Fall back atomically for incompatible fingerprints or layouts
- Preserve legacy deserialization and non-Responses behavior
- Cover capture, persistence, ordering, and fallback paths

This keeps multi-round prompts prefix-stable so provider-side prompt
caching can reuse prior reasoning and tool history.
Persist a stable prompt cache lineage independently from the concrete
session ID and inherit it when sessions retain a shared prompt prefix.

- Route provider caches by lineage instead of model or prompt scope
- Keep fresh subagents on independent cache identities
- Reuse lineage for forked, BTW, and branched sessions
- Pass request context through compaction summary requests
- Keep binding fingerprints separate for encrypted reasoning replay
Route BTW turns through the Desktop UI submission policy so the
runtime prompt retains the Chat Image Display context.

Pass the policy from the desktop adapter into the coordinator and
add regression coverage for the BTW output surface classification.
Remove model-binding fingerprints from persisted response replay state
and request context.

Forward valid encrypted reasoning items without local model filtering,
allowing the Responses service to determine compatibility while
retaining atomic fallback for malformed replay layouts.
The sidebar asked the user to pick a conversation *source* — Local or
Remote — before showing them anything. That is an implementation detail:
where a session runs is not how anyone looks for it, and the switcher cost
a permanent row of chrome to express it.

Conversations and workspaces now share one scroll. They are different kinds
of thing (a timeline and a set of places), so they stack rather than compete
for the same pane, and neither carries a label saying which machine it runs
on. The workspace section arrives through a `@BuilderParam` slot: the
sidebar has no business knowing about remote state, so the host wires it.

- Drop `ConversationSource` and `ConversationSourceSwitcher`.
  `AppRouteContract.conversationSource`/`routeForConversationSource` become
  `isRemoteRoute`/`remoteSurfaceDestination`, with `isRemoteRoute` stated as
  the complement of `isGeneralComposerRoute` so the two cannot drift apart.
  `remoteSurfaceDestination` resumes an in-flight remote session instead of
  dropping the user on a picker they did not ask for.
- Cap the conversation list at six rows behind an overflow row, so the
  workspace section stays visible on a phone without hunting for it. The
  shared scroll means the list can no longer take every pixel it wants.
- Fade rows out under the floating footer via a new `page_bg_fade` token
  (PAGE_BG at zero alpha, defined per theme). Without it a workspace row
  mid-scroll is visually sliced by the chat button sitting on top of it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The workspace section's "connect a desktop" row was wired to
`onSidebar.enterCode`, which only moves the visible surface to Remote.
Offline that resolves to `AppRoute.RemoteHome`, whose wide-layout detail
pane is `RemoteSurfaceHost` in placeholder mode: a header naming the
desktop the phone last held and two lines of status text, with no control
on it. So the row named the last-known machine on the right and then did
nothing, and pressing it again returned early on the `isRemoteRoute`
guard.

`RemoteSurfaceEntryPolicy` already states that reaching the remote surface
and asking to pair are different commands and must not share an entry
point. The row was on the wrong side of that line: give it
`onSidebar.connectDesktop`, which opens the connect sheet.

The section header's "+" shares the same event. Workspaces come from the
desktop and the phone cannot create one, so it is relabelled by the
connection it adds rather than a workspace it cannot make.

Also drop workspace entries with no path. `syncRemotePageSummary` seeds
the current workspace with the placeholder name 「未连接」 and an empty
path, and the projection turns any named current workspace into an entry.
On the Remote surface that never showed, because you only got there
connected; in the sidebar it is on screen from launch, so a reconnecting
phone with no workspace data yet listed a folder called 「未连接」 that
opens nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The back arrow on the desktop picker and on the account page sat visibly
left of the circle it lives in. Measured on device: circle centre x=422.5,
chevron ink centre x=399.5 — about 7vp adrift.

The cause is SymbolGlyph sizing, not the surrounding layout. A chevron's
natural advance box is roughly half as wide as it is tall (~11.6vp at
fontSize 23, against 23.2vp of height). Forcing .width(26).height(26) does
not re-centre the glyph in the enlarged box; it draws left-anchored, so the
ink lands 26/2 - 11.6/2 ≈ 7vp left of where the box centre says it should.
Vertically it looked fine only because the natural height already matched
the forced one. Probing the two glyphs side by side with tinted backgrounds
confirmed it: the unsized chevron's box measured 37px wide and centred in
the circle, while a magnifier forced to the same 26vp filled its box and
stayed centred, because its ink is square.

Dropping the forced size lets the Stack/Button centre the natural box.
Re-measured after the change: ink centre x=422.5 against a circle centre of
422.5.

Trailing chevrons elsewhere keep their forced width — there it acts as a
row gutter rather than as a centring box, and removing it would move the
rows rather than fix them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Git (since 2.35.2) and libgit2 refuse to operate on a repository whose
directory owner differs from the current user unless its root is listed in
safe.directory. BitFun surfaced that guard as an opaque command failure, so
read-only flows such as Review looked indistinguishable from "not a
repository" and blocked operations had no recovery path.

Repository ownership trust now lives in one platform-neutral module: owner
rejections are classified into a typed Git error, trust state is reported
without side effects, and safe.directory is written only after explicit user
confirmation, followed by a check that Git accepts the repository. The
confirmation flow works on local, remote, and peer surfaces: trust is applied
on the machine the user is on, while controllers receive the diagnosis and
the manual git command. The Git scene gains an authorization entry, Deep
Review target reads are serialized around a single trust decision, and prompt
dedupe keys are normalized per platform.
The crooked back chevron fixed in b48f60d was not a one-off. Probing on
device showed SymbolGlyph draws its ink left-anchored inside any box the
caller forces wider than the glyph's natural advance box (vertically it
stays centred, so only the horizontal axis is affected). Most symbols
have a square advance box of fontSize x 1.013, but chevron_left and
chevron_right are only half as wide as they are tall, so every
`.width(N).height(N)` on a chevron shifted it left of where the
surrounding container promised to put it.

Two shapes of the same bug:

- Glyphs inside a fixed-size centring Stack or circular Button: the
  forced box overrode the container's centring and pulled the icon off
  centre by up to 4.5vp. Dropping the size lets the container centre the
  natural box. Measured on the settings close button: ink centre now
  0.3vp from the circle centre, was ~7vp.

- Trailing disclosure chevrons in list rows: the forced 16-18vp box left
  ~10vp of dead space between the arrow and the row's right padding, so
  the arrows never lined up with the card edge. The right gap on the
  model row now measures 18.6vp against the 18vp padding.

Collapse indicators that toggle between chevron_right and chevron_down
keep their fixed slot -- it is what stops the label jumping between the
two states -- but the slot moves to a wrapping Stack and the glyph inside
it goes unsized, matching the idiom already used in SubagentTaskCard.
Verified on device that the label x is identical in both states.

Leading icon slots in list rows are left as they are: because ink is
left-anchored, the forced width is what keeps icon and text left edges
aligned across rows of differing fontSize.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
xielixing and others added 8 commits August 31, 2026 15:30
Replace the self-contained bundled JS worker with a typed LoopX host so task intake, workspace preparation, CLI supervision, and event delivery run through reviewed product-domain contracts instead of an embedded script runtime.

- Add LoopX product-domain contracts (policy, ports, types) under bitfun-product-domains.
- Add the LoopX controller assembly (store, agent adapter, event subscriber) in bitfun-core.
- Add concrete LoopX services (CLI process runner, GitHub intake, isolated workspace) in bitfun-services-integrations.
- Add the desktop miniapp_loopx_api Tauri surface and peer-host policy entries.
- Shrink the builtin bitfun-loopx web asset to a thin client that drives the host through the bridge (loopxBridgeProtocol, MiniAppAPI, useMiniAppBridge).
- Add contract tests for the LoopX ports, bridge, and thin-client source shape.
authorize_builtin compared app.runtime.content_hash (a hash of the MiniApp domain fields) against builtin_content_hash (a hash of the bundled asset files). The two hashes cover different inputs with different framing, so they can never match and the LoopX controller was always rejected as modified content.

Replace the comparison with builtin_source_matches, which compares the installed source files (html/css/ui_js/worker_js/esm_dependencies/npm_dependencies) verbatim against the bundled built-in bundle, excluding the meta.json identity/timestamp rewrite performed at seed time.
…th probe

The native-host migration dropped two behaviors the previous worker runtime provided.

- Restore the model dropdown: the thin client now populates the model <select> from the host model catalog through app.ai.getModels() and threads the chosen model id through resolveIntake/createTask.
- Add a pre-flight GitHub auth probe: refresh_environment now calls the new LoopxCliPort::probe_github_auth (a /rate_limit check) and populates the github_auth environment fact before intake, so an auth or rate-limit failure is visible up front instead of surfacing as a 403 at send time.
- Distinguish GitHub 403 rate-limit vs forbidden/private in the intake error message.
The restored dropdown called app.ai.getModels(), which is gated on the MiniApp AI permission and failed for the built-in LoopX app (which drives the native controller, not the raw AI bridge), leaving only the auto option. Add a dedicated loopx.listModels bridge method returning the host-configured chat models (same set as the main session picker), gated on the verified-builtin check instead of the AI permission, and register it in the peer/remote policy lists.
…-pane console

- thread host-resolved issue state and labels into the LoopX workflow plan
  instead of fabricating open-state metadata
- persist the source-backed candidate admission receipt at goal creation via
  workflow-plan --fetch-candidate-evidence --goal-id (best-effort, issue-kind
  items only) and persist the newer packet over the unconfigured plan packet
- teach the agent CLI contract the real issue-fix subcommands, the
  pr-lifecycle execute-transition form, and continuous_monitor cadence flags
- derive the goal objective from the resolved issue title
- add uuid to the miniapp-loopx feature and register its boundary ownership
- rework the bitfun-loopx console into task rail / task detail / timeline
  columns with a sticky owner-decision card pinned in the detail column
@xielixing
xielixing force-pushed the builtin/bitfun-loopx-miniapp branch from c45b4b2 to b35f2d5 Compare September 2, 2026 10:11
xlx1212 and others added 16 commits September 2, 2026 18:19
…request collapsed

- dispatch known issue-fix gate kinds (gated content read, maintainer
  clarification, authority grant, draft-ready) to human-oriented zh-CN
  headlines, explanations, and approve/reject effects with en-US parity
- stop rendering the agent's raw English todo text as the decision body;
  it moves into a collapsed 'original request' details block
- strip the [P0]-style priority prefix and adapt authority scope labels
  to the active locale
…nize issue view

- schedule exactly one corrective turn after a NoDurableProgress settlement,
  appending a host note that routes the agent back through the CLI write
  boundary instead of parking the task for manual recovery
- auto-approve read-only user gates surfaced by the settlement path (same
  policy as the drive-turn inspector, host-attributed and durably logged)
- project a decision card for waiting/recovery tasks from the durable summary
- remap recovery states to pending-approval/pending-recovery labels (amber,
  not error red) and drop the stale five-stage pipeline projection
- expand the Issue description panel by default and move it above the latest
  progress summary as the single status source
- hide routine engine heartbeat events and collapse thinking blocks in the
  merged timeline; remove the pause and resume-auto-follow controls
- carry tool input params on Completed/Failed/Cancelled tool events so late
  projections can render what ExecCommand ran and which file Read opened
- render only agent output blocks in the merged timeline; scheduler and
  engine heartbeat milestones are dropped (decision card + summary cover them)
- merge consecutive tool lifecycle events into one block whose text tracks
  the latest summary, and fold tiny text fragments into the previous block
- remember expanded thinking blocks across streaming re-renders and filter
  empty/marker thinking chunks
- default the issue view to the first task in execution order when nothing
  is selected
schedule_next_for_repository now also considers Preparing tasks: a task
reserved for workspace preparation whose drive never completed would keep
the whole serial repository line idle after the running slot freed up (the
scheduler previously only picked Queued tasks). Re-driving a Preparing task
is safe - reserve_repository bounces it back to Queued when the slot is
still taken. Parking settlements that fail to advance the queue now log the
remaining non-terminal task states so stalls are visible.
Thinking and text stream in as per-chunk events; the previous retention cap
(2400 events / 1.2M chars) evicted everything older than the last few rounds
within minutes, leaving the merged timeline with a handful of rows and an
unscrollable blank area. Raise the caps (50k events / 8M chars) and the
per-turn dedupe window (800 to 4000) to match chunk granularity.
Batch creation used to enqueue every task at once, letting concurrent
drive_task calls race for the repository slot; the winner could be the
last-created task, which both broke deterministic execution order and made
the default-focused task differ from the one about to run. Enqueue only the
first created task per repository and chain the rest through
schedule_next_for_repository after each settlement (Preparing tasks are
schedulable since the previous change). Also document the desktop target-GC
vs manual-build race in the desktop AGENTS guides.
Clicking the repository resume button could silently do nothing when the
resume target went stale between render and confirm. Both silent paths now
show an error notice so the failure point is visible.
The durable tool-activity events already carry a redacted input summary
(command, file path, pattern) in their details since the params projection
change, but the merged timeline's fallback rows rendered only the generic
'Tool completed: ExecCommand' label. Append the summary to the row message.
…ecution order

- the decision card now differentiates recovery from approval: interrupted
  work shows a primary 'resume retry' button (per-task resume), gate waits
  point at the approval panel
- the task rail and default focus follow actual execution order: running,
  preparing, queued (creation order), retry/waiting, recovery, then finished
  work most-recent-first - instead of scattering tasks by state priority
  with a most-recently-updated tie-break
- loopx_summary_v1 report contract: agent final responses end with a
  validated fenced JSON block (verdict / reproduction / segment kind /
  decision / blockers / next step with conditional evidence); the
  controller parses and persists it, the UI renders verdict badges and
  human-readable sections, falling back to raw text for legacy turns
- recovery_reason on task snapshots (host_restart, execution_failure,
  settlement_unverified, repository_paused, manual_restore), surfaced as
  a human explanation on the recovery card
- monitor-class todos (*_monitor, issue_fix_track_*) stop driving
  back-to-back turns: pinned v0.5.1 emits no numeric monitor_wait hint,
  so the host parks re-checks on a 15-minute compatibility cadence
  anchored to the last durable settlement and yields the repository slot
  to queued sibling issues; the depth-first sticky lane yields for
  monitor successors while real work segments still continue deep
- repository resume excludes tasks the agent already concluded as
  resolved upstream (mirrors the UI heuristic)
- agent re-entry instruction pins the exact quota spend-slot argv with
  the scheduler execution context declaration and appends the summary
  contract
- issue view: reproduction badge renders only when it carries signal
  (not_applicable hidden), technical facts folded into a collapsed muted
  block, dead five-stage pipeline code removed
- durable compensation allowance re-arms after a clean settlement
Runtime findings from the 2026-09-05 five-issue run (0/5 completed, all
parked in recovery) drive four behavior corrections:

- drive one autonomous replan turn when the plan runs dry with an open
  replan obligation: the pinned CLI v0.5.1 projects exactly that frontier
  and the quota guard admits it; parking there stranded every task before
  any goal could close. A todo-less RunNow frontier without an obligation
  still parks, now with an explicit plan_exhausted reason and a guided
  recovery card
- salvage the typed ok:false payload from turn-plan process exits when the
  replan frontier fails the host-bound route lineage check, so settlement
  and goal inspection degrade to the equivalent read-only projection
  instead of a raw process error
- carry the replan obligation through the goal snapshot and give replan
  turns an explicit re-entry clause requiring a typed --repair-delta-kind
  ACK (a delta-less ACK is stored as a no-op)
- recover completed-turn RetryRequired settlements (validated durable
  writeback, missing quota receipt) from the authoritative goal projection
  with a loud recorded event instead of a manual resume; cancelled and
  interrupted turns keep the explicit recovery path, and the host never
  retries or fabricates the receipt

Also corrects the MiniApp contract doc from the runtime data and syncs
the thin-client tests with the current UI contract (decision card,
execution-order rail, explicit publish grant, merged timeline), narrowing
the heartbeat lint to actual scheduling calls.
@GCWing

GCWing commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Thank you for your contribution.

The main branch has been replaced with the 1.0.0 codebase from 1.0.0-explore. As part of this migration and Git history cleanup, the affected pull requests have been temporarily closed.

If your changes are still needed, please reapply them on a fresh branch based on the new main, then open a new PR against main or update and reopen this PR. Please link any replacement PR to this one so we can retain the discussion and review context.

We apologize for the disruption and appreciate your understanding.

@xielixing

Copy link
Copy Markdown
Author

Replacement PR: #2836 (port of this work onto the 1.0.0 \main).

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.