feat(steward): make the steward prompts reachable from the Goal composer - #4591
Conversation
|
Revision after owner review (562ef9a): the whole quick-prompt row now sends on click and carries no state label.
Preview assertions: one row, labels |
|
Follow-up (f6c34d0), found by running the full personal-workspace smoke after the simplification. Making every chip send broke the durable contract in Validation after the fix:
|
`stewardPrompts` (ask what's next / what blocks / what is proven) existed in the client model but no workspace surface rendered it, so an owner had no steward affordance in the Goal conversation. Fold the two prompts that are not already covered -- blockers and evidence -- into the existing quick-prompt row instead of adding a second row, and take their text from `stewardPrompts` so the model stays the single source. "Ask what's next" is skipped: the row's existing next-action chip already covers it. The two chips act immediately, matching the existing progress-report chip, so one click produces an answer instead of a draft the owner must then send. Validated: `tsc --noEmit` exit 0, `workspace-theme contract: ok`, and a browser preview asserting exactly one quick-prompt row, no duplicate chip row, the five labels, an empty composer after clicking, and the steward gate prompt sent as a Turn. Preview screenshots were reviewed by the owner before this commit. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
The quick-prompt row distinguished draft chips from immediate chips with a label on every chip, so an owner had to read a badge to know whether a click would send. The row now uses one neutral chip style: every prompt is delivered on click, the draft/immediate badges and their labels are gone, and the draft helpers that only existed for those chips are removed. Goal row: ask-what's-next, progress report, scheduled check, blockers and evidence all send. Manager row: tasks and all-Goals-progress send; creating a Goal stays an action, not a message, so it keeps opening the Goal draft. The scheduled-check chip sends its template as-is; the check target is the one field the owner still supplies in the conversation. `workspace-theme.test.mjs` encoded the old badge rule, so it now asserts the simplified contract: one neutral chip style and no badge class anywhere. Validated: `tsc --noEmit` exit 0, `workspace-theme contract: ok`, and a browser preview asserting one row, the five clean labels, no badge text, an empty composer after clicking, and the prompt delivered as a Turn. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Making every quick prompt send broke the durable scenario contract: the scheduled-check chip must still put its template in the composer, because the check target is the one field the owner has to supply and typed-actions asserts the draft carries it. Only the message prompts send on click; the chip keeps no badge, so the row stays label-free. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
… row Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
The scheduled-check shortcut was the last chip that filled the composer instead of sending, so an owner had to click, read a template with an empty check target, and press send. It now delivers its bounded request on click like every other chip: the message names the check target, frequency and stop condition, so the confirmation card carries a concrete target the owner can still adjust before anything is created. `typed-actions.mjs` asserted the old draft contract in both locales; it now asserts the shortcut maps to one `monitor.create` preview with cadence `2h`, stop condition `goal_complete`, the localized default check target, and zero durable writes before confirmation. `personal-workspace-contract.test.mjs` repeated the draft wording, so its two shortcut assertions now describe the send-on-click contract. That file is not wired into a smoke runner and still fails on an unrelated `onOpenGoal` assertion; this change only stops it encoding the retired draft behavior. `composer.monitorHint` described the retired draft boundary and is removed from both locales. Validated: `tsc --noEmit` exit 0, `workspace-theme contract: ok`, and `typed-actions` in development mode 3/3 passing. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…k shortcut Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
7a5295b to
1f6df5c
Compare
|
Owner first-screen approval recorded for exact head
The PR cannot merge yet for a reason unrelated to its diff: the required |
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
712add5 to
a10a93c
Compare
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
|
Owner first-screen approval re-anchored to the current head The owner reviewed the Goal-composer quick-prompt row previews captured after tip commit The source and the shipped What still holds this PR is not the first screen. |
…over (#4612) `test_turn_context_reads_a_bounded_window_and_declares_sources` built six days of receipts at `datetime.now(timezone.utc)` minus `(days_ago, minutes=index)`. When the shard runs between 00:00 and 00:11 UTC the oldest row lands on a seventh UTC date, so a correct 7-day window reports seven day buckets and the assertion `len(matched_by_day) == 6` fails. PR #4591's test-shard (1) failed exactly that way at 2026-09-17T00:08:46Z. Anchor the newest receipt to 18:00 UTC on the previous UTC day, which keeps every row in the past and at least eleven minutes inside its own UTC date, so the fixture exercises the per-day and total bounds instead of the wall clock. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Co-authored-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
|
Head re-anchored to #4612 landed the required-check repair (squash merge The approved first screen is unchanged by the re-base, so the owner's |
huangruiteng
left a comment
There was a problem hiding this comment.
动机
两件事同时收口:一是 owner 的明确要求“全都改成立即发送,且不用标注『立即发送』,这样界面简洁”;二是本车道记录的 journey gap 1——管家有界提示集只存在于客户端模型里,对话里点不到。这个 PR 让提示行成为真正的入口,而不是要求 owner 先打字或先清草稿。
改动思路
以客户端 stewardPrompts 作为唯一来源,提示行只做投递:每个 chip 点击即发送自己的消息,草稿/立即发送徽标与其对应 i18n 键一起删除,新增“看阻塞”“查证据”两个 chip;定时检查 chip 也从“填草稿”改为发送带本地化默认检查目标的模板,但仍停在既有的 monitor.create 确认卡片,确认前零 durable write。
具体改动
- i18n:删除
composer.draft、composer.immediate、composer.prepareDraft、composer.monitorHint,新增composer.blockers、composer.evidence、composer.monitorShortcutTemplate(英文与 zh-CN 同步)。 - personal-workspace-page.tsx:
fillQuickPrompt换成sendMessage,选中 Goal 时五个 chip、未选 Goal 时三个 chip,发送中禁用。 - CSS:移除
.is-draft/.is-immediate/.personal-prompt-badge及其主题覆盖,改为button:disabled态。契约测试与 typed-actions smoke 由“只填草稿”改为断言点击即发送;loopx/web/chat随包 bundle 重建。
对主干的风险
删除 i18n 键的风险已核实:在该 head 上 git grep "composer\.\(draft\|immediate\|prepareDraft\|monitorHint\)"(排除 bundle 产物)无任何残留引用,唯二命中是无关的 loopx-pw-composer-drafts sessionStorage 键。定时检查语义仍受确认卡约束,不会因为少填草稿就多出 durable write。我在这条分支的 head 上实测:开发态与打包态(从 /chat/ 服务)steward-journey 都通过,beats=4、gaps 只剩 3-confirm 与 4~7,说明“提示行可达并点击即发送”这一拍已从 gap 变为 proven。首屏门禁方面,owner 已在 确认首屏 中确认同一份呈现,重新 base 后 apps/presentation/dashboard 与 loopx/web/chat 与获批树逐字节一致(PR 评论 5706730202)。
我的整体评价
把“界面简洁”的直觉要求和“提示可达”的旅程缺口一次收口,且没有用静默行为换取简洁(定时检查仍走确认)。建议在该 head 的必过检查转绿、owner 结清合并决定后合并。
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Head: 18153d1
English verdict: APPROVE
…ng it The steward journey recorded its prompt row as gap 1 because the bounded prompt set lived in the client model while the conversation could not reach it. PR loopx-project#4591 shipped the row, so the scenario now asserts the shipped contract: the row must expose the five released labels, clicking 看阻塞 must post its message as an accepted Turn, and the composer must stay empty afterwards. A regression fails with the missing labels named, so it cannot pass silently. Both locale mirrors renumber the remaining gaps and record why the prompt row is no longer one of them. Validation: steward-journey in development and packaged modes; the negative control (row buttons removed) fails naming 看阻塞 / 查证据 as missing; the full seven-scenario personal-workspace development suite; workspace-theme contract; docs-governance-smoke; docs-asset-integrity-smoke; loopx check --scan-path over the three changed files (errors=0, boundary scan clean). Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Goal And Delivered Outcome
Source: owner feedback on the journey scenario's gap 1 (
stewardPromptsdefined in the client model but unreachable from the conversation), with the first-screen preview reviewed and approved by the owner before this commit.Before: the Goal composer offered next-action, progress-report and schedule chips; the steward's blocker and evidence prompts had no surface at all.
After: the existing quick-prompt row carries two more chips,
看阻塞(Ask what blocks) and查证据(Check what is proven), whose prompt text comes fromstewardPrompts, and both act immediately like the existing progress-report chip.Scope And Continuation
Changed surfaces:
apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx(two chips in the existing row plus one small prompt-text lookup) andi18n.tsx(EN/zh labels). Frontend-only: no protocol, kernel, permission or scoring change.Deliberately not done:
询问下一步,配置定时检查) — if those should also send directly, that is a separate behavior decision.Follow-up once this lands: flip gap 1 from gap to proven in the journey scenario (PR #4588) and in the product case (PR #4589), both still open.
Public And Private Boundary
No fixture, no local path, no live Goal or agent data. The preview used the existing synthetic browser fixture; screenshots stayed in the gitignored output path.
Validation
.personal-quick-promptsrow, no duplicate chip row, labels询问下一步 / 向 Agent 获取进度报告 / 配置定时检查 / 看阻塞 / 查证据, composer empty after clicking看阻塞, and the steward gate prompt delivered as a Turn; no client-side errors.tsc --noEmitexit 0;workspace-theme contract: ok.