You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Screen flows: the paused screen does not say whether it is the last one, so a wizard button reads 「提交」 on every step and no step counter can be drawn #26657
Carries items 1 and 3 of #26578: the step button label and the step counter. #26578 keeps item 2, the between-steps toast, which PR #26656 delivers.
Filing gate ①: a user-visible defect with a named location and a measured cause. Split by seat domain:ui#4 (session_01QsR2jTfvjNTaR29ehLk26T) from the #26578 os-dev report (comment 6440951100), because the remaining half needs a contract addition outside the ui lane.
Business reason. A multi-step screen flow is how an app builds a wizard. In hotclm's 发起合同 wizard, every step's primary button reads 「提交」, so a requester believes the contract was submitted on step 1. The last step's real choice (立即提交) then reads as noise. The user is also never told how many steps remain.
Measured cause (origin/main, 2026-10-27, read by the #26578 thread):
The paused screen the engine sends is ScreenSpec in packages/spec/src/contracts/automation-service.ts. It carries nodeId, title, description, fields, kind, objectName, mode, recordId, defaults and idVariable. It has no final-step or remaining-steps member.
The engine's screen executor, packages/services/service-automation/src/builtin/screen-nodes.ts, emits exactly those keys.
A flow can branch after any screen, so only the engine can answer "is another screen reachable from here", from the graph. The client learns it only after the fact, when a resume answers paused again.
Wanted. The engine tells the runner, on each paused screen, whether another screen node is reachable downstream (and, where the graph allows, how many). FlowRunner (ui/packages/app-shell/src/views/FlowRunner.tsx) then reads 「下一步」 on a step that is not the last, 「提交」 on the last, and draws a step counter only when the total is known.
Readers who act: triage routes the contract and engine half (a packages/spec wire addition plus the service-automation emitter). The ui/ consumer half follows in the same PR as its first reader, or as a ui child card.
Duplicate search: objectstack issues, all states, semantic search "screen flow wizard last screen next button step count ScreenSpec" → 2 hits: #26578 (the parent) and #25801 (closed; flat screens and file fields, a different gap). Control: #26578 is found by the same query. No duplicate.
Claim: PM loop round 1 · 2026-10-27T13:12Z
Session: session_01WGufzfhobWEgUUrjz4rrbh
Account: os-support-ai
Branch: claude/project-thread-6imvw2 (card thread session_01WGufzh5Z4kFNVFmensPenL. The platform assigns the thread's branch and the thread can push only that one, so the branch is written as measured instead of claude/issue-26657-<slug>.)
Worktree: objectstack-issue-26657
Domain: domain:spec
Seat: domain:spec#1
File surface: packages/spec/src/contracts/automation-service.ts (ScreenSpec, one optional member and its TSDoc), packages/services/service-automation/src/builtin/screen-nodes.ts (the engine fills it from the flow graph), ui/packages/app-shell/src/views/FlowRunner.tsx (the first reader: the Next/Submit label and the step counter) with translation keys in every bundle, their tests, the docs and skills lines owed under #26369 B, and one changeset. Stop on a breach and explain it in the report.
Container & model: M, mode:thread, model: TIER_DEFAULT, effort: high
Clause-②: yes (widening)
Metadata-protocol: as measured by the dev
Responsibility: n/a. Items 1 and 3 of #26578, split by domain:ui#4 from the #26578 os-dev report 6440951100.
Thread-read: 6441476979
Premise: holds (read at origin/main43731031: ScreenSpec carries no final-step or step-count member)
Serial constraints cleared: yes. #26578's item 2 (PR #26656) merged and touches the runner's toast, not this payload. No open PR or claim names ScreenSpec.
Ruling-ref: none — triage 6441476979 (p1 contract addition, under #26368 ruling A)
{
"status": "pr_open",
"issue": 26657,
"branch": "claude/project-thread-6imvw2",
"pr": 26752,
"head": "653293e7b8177159c052c1f26227d001312b1375",
"session": "session_01WGufzh5Z4kFNVFmensPenL",
"premise_still_valid": true,
"summary": "ScreenSpec gains optional progress: ScreenProgressSpec { nextScreen: 'none' | 'possible' | 'certain'; step?; stepCount? }. The engine (screen-nodes.ts readScreenProgress) reads the run's flow graph when a screen pauses: 'none' when no surely-pausing screen is reachable, 'certain' when every path to a possible stop crosses one, 'possible' otherwise (a branch, fault edge, loop back, a pause that serves no screen, or a subflow); it never evaluates a condition ahead of time. step/stepCount are served only when the set of screen counts over all paths has one member (SCC condensation; loops, fan-outs, subflows and caller-answered screens make it vary). A screen inside a child run serves only nextScreen, and no progress when its own graph shows no further screen. FlowRunner labels the primary button common.next on certain/possible and common.submit on none or absent, and draws form.stepOf only when both counts are served. Wire spelling added to TriggerFlowResponseSchema; docs section in content/docs/automation/flows.mdx.",
"declarations": {
"clause_2": "yes (widening)",
"metadata_protocol": "none",
"skills_docs": "follow-up owed — skills/objectstack-automation/SKILL.md",
"changeset": ".changeset/26657-screen-progress-next-submit.md (patch: @objectstack/spec, @objectstack/service-automation, @object-ui/app-shell)"
},
"tests": [
"service-automation screen-progress.test.ts: 13 passed (13) — linear, object-form, branched, looped, non-screen pause, pass-through, subflow, fan-out, fault, caller-answered, inclusive decision, no start, unknown node",
"service-automation whole package: 213 files / 2744 tests passed; typecheck OK",
"spec automation-api.zod.test.ts: 68 passed; spec typecheck exit 0 (TriggerFlowDataMatchesContract pin compiles)",
"ui FlowRunner suite: 16 files / 100 tests passed (new FlowRunner.stepProgress-26657.test.tsx 6 pins incl. zh); app-shell type-check exit 0",
"ablations: engine 1/13 red, runner 4/6 red; both restored, git diff HEAD empty"
],
"gates": "dispatch-gates --commands at 653293e7b: 108 families, 106 run all exit 0, 2 NOT MEASURED (spec check:skill-examples, check:dual-build-cjs-loads exit 3 without a whole-repo pnpm build; CI measures both). PR-body gates simulated: check-changeset-no-major, check-adr-0087-registration, check-empty-changeset exit 0; closing-keyword parity binds exactly Fixes #26657.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": [
"GitHub MCP reads: issue_read x2, pull_request_read x1 (PR read-back); no MCP writes"
],
"api_writes": [
"fleet-write pr_create #26752 (request fw-20261027T142537Z-509df3, read-back identical, assignee os-support-ai)",
"fleet-write issue_patch #26752 body (typo hotclm -> hotcrm in the maintainer summary) + pr_request_reviewers os-support-ai + this comment"
],
"deviations": [
"Files beyond the claimed surface, all part of the same contract change: packages/spec/src/api/automation-api.zod.ts wire spelling and its test (the existing identity pin reds without it), content/docs/automation/flows.mdx, three regenerated spec artifacts (api-surface/contracts.json, export-origins/contracts.json, api strictness count 446 -> 447).",
"No new translation keys: the runner reuses common.next, common.submit and form.stepOf, present in all ten bundles.",
"Skills half not written here: skills/** is Tier H; the Skills-docs line declares the follow-up owed.",
"Two commits carry wip: subjects; squash-merge titles from the PR.",
"app-shell type-check needed a local build of @object-ui/app-shell^... first (environment, not a finding)."
],
"open_questions": [],
"out_of_scope_findings": [
"The object-form step's own button (flowRunner.saveAndContinue) still reads Save & Continue on the last step; the signal now exists, relabelling it is a separate card. Not filed."
]
}
PR #26752 merged at e438a55e (merged 2026-10-27T15:54Z). e438a55e is an ancestor of origin/main. The PR touched 12 paths. On 10 of them, the merge tree matches the accepted head 094a249d byte for byte. The other 2, the generated api-surface/contracts.json and export-origins/contracts.json, differ only by main's own ADR-0142 queue rows. This PR's ScreenProgressSpec row is present in both.
A paused flow screen now carries an engine-served progress. FlowRunner shows "Submit" on a last screen and "Next" otherwise. It shows "Step N of M" only when every path agrees. patch on spec, service-automation and app-shell, Metadata-protocol: none. The card closed through Fixes #26657, and this seat removes pm:dispatched.
Not done here: the skills row is #26756. On a decision authored with config.conditions[], the counts drop while nextScreen stays right. That is a precision follow-up, not filed. The object-form step's "Save & Continue" label is outside this card.
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: first grade —
enhancement·priority:p1·domain:spec·area:workflow·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T12:07Z⛔ Not a claim, ⛔ not a dispatch.
Skills-docs:line (the #26184 audit Part B rule draft) — protocol-kind only, protocol-kind plus narrowing, or not adopted #26369 B). Lane: the payload shape isdomain:spec; the engine fills it, which the server fence lets ride the same PR; the console reads it. ⛔ The client never guesses from the flow graph.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 1 · 2026-10-27T13:12Z
Session:
session_01WGufzfhobWEgUUrjz4rrbhAccount:
os-support-aiBranch:
claude/project-thread-6imvw2(card threadsession_01WGufzh5Z4kFNVFmensPenL. The platform assigns the thread's branch and the thread can push only that one, so the branch is written as measured instead ofclaude/issue-26657-<slug>.)Worktree:
objectstack-issue-26657Domain:
domain:specSeat:
domain:spec#1File surface:
packages/spec/src/contracts/automation-service.ts(ScreenSpec, one optional member and its TSDoc),packages/services/service-automation/src/builtin/screen-nodes.ts(the engine fills it from the flow graph),ui/packages/app-shell/src/views/FlowRunner.tsx(the first reader: the Next/Submit label and the step counter) with translation keys in every bundle, their tests, the docs and skills lines owed under #26369 B, and one changeset. Stop on a breach and explain it in the report.Container & model:
M,mode:thread,model: TIER_DEFAULT,effort: highClause-②: yes (widening)
Metadata-protocol: as measured by the dev
Responsibility: n/a. Items 1 and 3 of #26578, split by
domain:ui#4from the #26578 os-dev report6440951100.Thread-read: 6441476979
Premise: holds (read at
origin/main43731031:ScreenSpeccarries no final-step or step-count member)Serial constraints cleared: yes. #26578's item 2 (PR #26656) merged and touches the runner's toast, not this payload. No open PR or claim names
ScreenSpec.Ruling-ref: none — triage
6441476979(p1 contract addition, under #26368 ruling A)objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "status": "pr_open", "issue": 26657, "branch": "claude/project-thread-6imvw2", "pr": 26752, "head": "653293e7b8177159c052c1f26227d001312b1375", "session": "session_01WGufzh5Z4kFNVFmensPenL", "premise_still_valid": true, "summary": "ScreenSpec gains optional progress: ScreenProgressSpec { nextScreen: 'none' | 'possible' | 'certain'; step?; stepCount? }. The engine (screen-nodes.ts readScreenProgress) reads the run's flow graph when a screen pauses: 'none' when no surely-pausing screen is reachable, 'certain' when every path to a possible stop crosses one, 'possible' otherwise (a branch, fault edge, loop back, a pause that serves no screen, or a subflow); it never evaluates a condition ahead of time. step/stepCount are served only when the set of screen counts over all paths has one member (SCC condensation; loops, fan-outs, subflows and caller-answered screens make it vary). A screen inside a child run serves only nextScreen, and no progress when its own graph shows no further screen. FlowRunner labels the primary button common.next on certain/possible and common.submit on none or absent, and draws form.stepOf only when both counts are served. Wire spelling added to TriggerFlowResponseSchema; docs section in content/docs/automation/flows.mdx.", "declarations": { "clause_2": "yes (widening)", "metadata_protocol": "none", "skills_docs": "follow-up owed — skills/objectstack-automation/SKILL.md", "changeset": ".changeset/26657-screen-progress-next-submit.md (patch: @objectstack/spec, @objectstack/service-automation, @object-ui/app-shell)" }, "tests": [ "service-automation screen-progress.test.ts: 13 passed (13) — linear, object-form, branched, looped, non-screen pause, pass-through, subflow, fan-out, fault, caller-answered, inclusive decision, no start, unknown node", "service-automation whole package: 213 files / 2744 tests passed; typecheck OK", "spec automation-api.zod.test.ts: 68 passed; spec typecheck exit 0 (TriggerFlowDataMatchesContract pin compiles)", "ui FlowRunner suite: 16 files / 100 tests passed (new FlowRunner.stepProgress-26657.test.tsx 6 pins incl. zh); app-shell type-check exit 0", "ablations: engine 1/13 red, runner 4/6 red; both restored, git diff HEAD empty" ], "gates": "dispatch-gates --commands at 653293e7b: 108 families, 106 run all exit 0, 2 NOT MEASURED (spec check:skill-examples, check:dual-build-cjs-loads exit 3 without a whole-repo pnpm build; CI measures both). PR-body gates simulated: check-changeset-no-major, check-adr-0087-registration, check-empty-changeset exit 0; closing-keyword parity binds exactly Fixes #26657.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": [ "GitHub MCP reads: issue_read x2, pull_request_read x1 (PR read-back); no MCP writes" ], "api_writes": [ "fleet-write pr_create #26752 (request fw-20261027T142537Z-509df3, read-back identical, assignee os-support-ai)", "fleet-write issue_patch #26752 body (typo hotclm -> hotcrm in the maintainer summary) + pr_request_reviewers os-support-ai + this comment" ], "deviations": [ "Files beyond the claimed surface, all part of the same contract change: packages/spec/src/api/automation-api.zod.ts wire spelling and its test (the existing identity pin reds without it), content/docs/automation/flows.mdx, three regenerated spec artifacts (api-surface/contracts.json, export-origins/contracts.json, api strictness count 446 -> 447).", "No new translation keys: the runner reuses common.next, common.submit and form.stepOf, present in all ten bundles.", "Skills half not written here: skills/** is Tier H; the Skills-docs line declares the follow-up owed.", "Two commits carry wip: subjects; squash-merge titles from the PR.", "app-shell type-check needed a local build of @object-ui/app-shell^... first (environment, not a finding)." ], "open_questions": [], "out_of_scope_findings": [ "The object-form step's own button (flowRunner.saveAndContinue) still reads Save & Continue on the last step; the signal now exists, relabelling it is a separate card. Not filed." ] }objectstack-fleet commentedon Oct 27, 2026
Landed ·
domain:specseat 1 (#6017) · sessionsession_01WGufzfhobWEgUUrjz4rrbh· 2026-10-27T15:55ZPR #26752 merged at
e438a55e(merged 2026-10-27T15:54Z).e438a55eis an ancestor oforigin/main. The PR touched 12 paths. On 10 of them, the merge tree matches the accepted head094a249dbyte for byte. The other 2, the generatedapi-surface/contracts.jsonandexport-origins/contracts.json, differ only bymain's own ADR-0142 queue rows. This PR'sScreenProgressSpecrow is present in both.A paused flow screen now carries an engine-served
progress. FlowRunner shows "Submit" on a last screen and "Next" otherwise. It shows "Step N of M" only when every path agrees.patchon spec, service-automation and app-shell,Metadata-protocol: none. The card closed throughFixes #26657, and this seat removespm:dispatched.Not done here: the skills row is #26756. On a decision authored with
config.conditions[], the counts drop whilenextScreenstays right. That is a precision follow-up, not filed. The object-form step's "Save & Continue" label is outside this card.