Skip to content

fix(goal): expire pause controls across resumed turns - #1

Merged
new-Beginner merged 32 commits into
feat/autonomous-goal-9ba23afrom
fix/goal-pause-resume-9ba23a
Nov 6, 2026
Merged

new-Beginner merged 32 commits into
feat/autonomous-goal-9ba23afrom
fix/goal-pause-resume-9ba23a

Conversation

@new-Beginner

Copy link
Copy Markdown
Owner

Refs vastsa#1999

第一阶段最小修复

目标分支是 vastsa#1999 的 feat/autonomous-goal-9ba23a,不是 main。以原 PR 最新 head 6ae2428dd2f039bd30109a2a1817e4a33853d84b 为输入,保留其完整历史,不重写或直接推送该分支。

实际修复:c36aeb321a4949711bf756c8885d4fc68cb806d5:10 文件 +167/-22,其中生产源码仅 5 文件 +24/-7;其余为必要回归和两处规范同步。

  • 暂停 steering 改为 Desktop-owned goal_pause 系统分段,按当前已验证 GoalTurn 的 closeout 状态合成;新 claim、普通 Agent 工作和移除后的转换不继承旧暂停命令。复用现有分段覆盖/清空机制,不新增数据库或协议字段。
  • 压缩检查点不保留临时暂停分段。兼容读取内部 model-system 历史中的旧版完整固定通知、已折叠检查点及 retained tail,不改写原始持久历史;不匹配普通用户/工具文本,保留其他系统指令、引用、安全约束和工具声明。
  • 暂停期间的执行拒绝、至多三次后续模型请求、禁止自行恢复等边界保持。不加入第二阶段无进展熔断,不改预算或计轮契约。

基线同步单独提交

879268855 是无手工冲突解决的自动合并基线,纳入最新 main d4f5c10f371c373485342a59a5b364356189f70f。vastsa#1999 尚未包含这批 main 提交,因此整体比较页也会显示既有主干变更;请用上面的 c36aeb3 单独提交审阅本次最小修复。基线同步与行为修复没有混在同一个提交。

必要验证

  • 修改前 5 项断言红灯:3 项系统历史/检查点和 2 项运行时恢复,均因旧暂停指令残留失败。修复后转绿。
  • 4 个定向文件 83/83 通过:Goal runtime、system transcript journal、system transcript、session context。覆盖热恢复、冷加载旧记录、两种检查点、用户安全/引用保留及原有暂停限制。provider failure 用例为合成夹具,并非真实付费调用。
  • 真实 Rust Host + 当前候选 sidecar + AgentHost:11 个回环合成模型请求通过。显式恢复后的实际请求无旧暂停命令,原生 Read 返回真实隔离文件;再次 Pause、替换 Goal、FIFO、1 次配合收尾和 3 次不配合收尾上限保留。
  • 相关 TypeScript 构建、8 个改动代码/脚本文件 lint、architecture、agent-policy、diff 和 check:pr-base 通过。
  • 最终 E2E 绑定 c36aeb321a4949711bf756c8885d4fc68cb806d5,main 为 d4f5c10f371c373485342a59a5b364356189f70f。Rust 源码与原 feat(goal): add durable autonomous goals with attached controls vastsa/PI-Desktop#1999 候选相同,复用同源码 release Host(SHA256 63128f6a68953eefd51eeb7dfdec747166064b247a06a363c6e73ab3c511b960),没有重装依赖。

按快速、最小范围要求,未运行全仓测试/构建、跨平台套件、verify:ui:*、真实提供商请求或发布安装。没有操作真实问题会话,也没有上传私有报告、原始日志或数据库。远程 Checks 以新 PR 的实际结果为准,不以 vastsa#1999 旧 head 的 CI 代替。

v_wyxgwang and others added 30 commits November 5, 2026 11:18
The 34px icon left room for a type badge but not for the name: at the previous default width a tile had about 40px of text and truncated after three characters. Every source now renders the same 48px rounded square, the badge is gone, and the name owns the whole line under the icon.

The window opens at 900 DIP and refuses to go below 800, which is the narrowest width where an eight-column row still fits the icon and a readable name. The trade-off is explicit: a plugin and an application look identical until one is opened, and the hover title is the only place that still names the source.
The spec still described a type badge, a square/round split and a 560 minimum width. It now states the two-part tile, the 48px shape, the 800/900 width floor and default, and that telling a plugin from an application is a deliberate non-goal covered only by the hover title.

The ADR records the same trade-off in its consequences, and E2E-268 gains a same-name step so the behaviour is checkable by hand.
Brings the tile change onto the current base; no conflicts, the merge is purely additive against the launcher files.
A Markdown link whose destination names a real directory failed in two
independent places (issue vastsa#2113):

- normalizeMarkdownFilePath waived no heuristics for drive-anchored
  destinations, so an extension-less directory fell out of normalization
  and rehype-sanitize stripped the href as an unknown c: scheme — the
  anchor rendered with no target at all. A link destination is an
  explicit reference (the rule markdownLinkFileTarget already applies),
  so normalization now keeps the same acceptance and encodes the path.
- resolveChatFileRef required a regular file at every tier, so the open
  flow reported a missing file for a path that exists. Exact references
  can now name a directory inside the managed roots when the caller
  passes allowDirectory: the match carries target "directory" and the
  chat open flow browses it in the file manager. Shorthand and fuzzy
  completion never set the flag, so a directory named like a file keeps
  answering nothing (the pinned contract), and directories outside the
  managed roots stay outside the ADR 0339 file contract.

Explicit Markdown links and tool-arg chips set the flag; the bundled
file manager already reveals a directory location by expanding its
ancestors, so no plugin change is needed.
The bundled File Manager answered a host location that names a directory
by dispatching fm.read, which refuses directories (INVALID_PATH "path is
a directory") — the PR review reproduced this against the shipped
handler, so the chat open flow produced a tab whose tree was collapsed
and whose reader had failed.

Rebuild the vendored view with a directory-aware receiver (Desktop
hotfix 0.9.1-pi.2, the 73d8932 convention — no minified JavaScript is
edited by hand; the patch carries the source change and the provenance
record carries the new checksums):

- classifyHostOpenTarget (views-src/src/lib/hostOpen.ts) reads the
  target's identity from the already-loaded parent listing; a missing
  listing stays conservative and keeps the file path.
- applyHostOpen expands a classified directory, loads its entries and
  shows the tree instead of collapsing it over an unreadable preview;
  ordinary files keep their exact previous flow.
- failureMessage translates the production directory rejection into a
  localized message for references outside the managed roots (scratch),
  which stay un-browsable — containment unchanged, main.js untouched.

Boundary tests execute the shipped main.js: reads refuse directories in
both addressing modes, lists answer directories and refuse files, and
ordinary files read as before. The Electron journey drives the real
view over the real plugin process for primary, sibling-root and scratch
directory locations plus ordinary-file behavior. The rebuilt view is
byte-reproducible from the pinned integration commit with the two
checked-in patches applied.
…grid

feat(plugin-launcher): one 48px rounded tile per item and a wider panel
With the Count badge and the Activity rail both enabled, a project header
rendered the same running and permission-waiting figures twice: the rail's
numeric readout is documented as the badge's stand-in, yet both call sites
gated it on the rail switch, so turning the rail on duplicated the counts
side by side.

`resolveSidebarRunningAffordances` now owns that exclusivity rule as
`railCount`, and the local and remote headers render the readout from it,
so one figure appears once per group while each sub-switch still hides only
its own affordance.

The sidebar IA spec, its zh-CN mirror, and the E2E-266 expectation record
the ownership rule.
The first CI run of the directory journey exposed a first-frame race the
review repro did not: the host location is released as soon as the
project group is applied, which can precede the root listing, so the
classifier read an absent listing, answered unknown, and the open fell
back to the file read — exactly the failure this hotfix removes. The
receiver now loads the parent listing (loadDirectory is idempotent, so
an already-loaded parent costs no extra channel call) before asking
what the location names; a listing that then lacks the entry still
falls back to the file path and reports accurately.
…icate

fix(sidebar): print one running count per project header
The journey's preload stub omitted pi.fs, so the real handleHello threw
on its bare-typeof openInBrowser probe and the view mounted without the
workspace — the directory scenario then timed out on an empty tree. Add
the fs surface the hello answers on, and the setSettings write the
sibling-root switch issues.
The model menu hid everything beyond three recent models behind an
"Other models" disclosure, then dumped every provider into one long
list. Finding a model meant expanding and scrolling.

The menu now pairs a source rail (Recent, then each provider with its
model count) with a pane listing the chosen source's models, so every
configured model is one click away. Search spans all providers and dims
sources without matches. The pane height is fixed by the tallest source
so switching or typing never resizes the menu, and the reasoning slider
sits in its own footer.
Two-pane Composer model picker with a source rail.
Two CI runs failed on the same bare timeout, so the journey no longer
fails blind: the preload records every bridge call (channel, verdict,
result head) and exposes the log to the page, a preload crash is carried
as its own diagnostic, waits extend to 15s, and a scenario that never
reaches its expectation dumps the full page state — rows, selection,
banners, body sample, channel log — into the probe line.
The bridge:false failure modes are preload crashes, and the one
diagnostic that names them was exposed to the page but never read back.
readState now returns __preloadError alongside the channel log.
The preload crash finally named itself: main.js requires its sibling
./remote-workspace.js, and the fixture staged main.js alone, so the
require failed, the bridge never mounted, and every scenario timed out
on the no-bridge empty state. Stage both runtime files.
The journey's channel log pinned the real defect: both root listings
had answered with the directory entry before the read was dispatched,
so the miss was not the first-frame race but the read-back —
directories state reaches dirsRef through a render, and the open
chain's microtask continuation still saw the previous map, so the
classifier answered unknown and the flow fell back to the file read.
loadDirectory now returns the entries it saw (cached hits included)
and the receiver classifies against that value directly.
…asoning

The first two-pane picker read heavy: colored monogram tiles in the
source rail, a filled slab on the current row, and a dot-rail reasoning
slider that did not match the compact rows around it.

The rail is now text only with one marker that slides between sources,
the model pane slides in from the direction of the move, and the current
row gets a drawn check instead of a fill. Search becomes a flush header
with a clear button, and Escape clears a typed search before closing.
Reasoning is a segmented track in the footer with a raised pill; the
native range still owns keyboard, drag and accessibility, and the D458
column geometry is unchanged (D685).

The reasoning layout fixture was missing recentEntries, so the Electron
geometry check could not open the menu; it now runs and covers the
segmented control.
Refine the Composer model picker: text rail, segmented reasoning control.
The locale check requires the Chinese decisions log to keep the English
table shape, so the new D685 row needs its translated counterpart.
Keep Electron alive between scenarios and assert actual file-read calls. The editor DOM is mounted even without a file, and a nested managed root keeps its primary-relative address.
Include the new presentation component and real directory prompt parser in the existing isolated transcript harnesses so unrelated message regressions remain covered.
Validate the directory receiver and repaired journey against the current target branch.
…-redesign

feat(composer): two-pane model picker with a text rail and segmented reasoning
…e-layout-20261106

fix(composer): show pasted folders above prompt text
Include the landed composer fixes and picker changes before validating the directory link candidate.
fix(chat): open explicit directory links in the file manager
Keep the repair candidate based on current main while preserving the\nexisting Goal branch history. The lifecycle fix is a separate commit\nso its small behavioral diff can be reviewed independently.
Scope pause steering to the current validated closeout through a
replaceable system section, rather than append-only prompt content.
Restore legacy controls as inert history without rewriting saved data.

Cover warm resume, cold legacy replay and compaction while preserving
real user constraints, tool access checks and bounded handoff behavior.
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.

5 participants