Repository navigation
feat(core): bind @-workflow confirms to a real WorkflowRun of the chosen snapshot - #71
Conversation
Pending WorkflowRun details must retain JSON null for startedAt and finishedAt instead of invalid empty date-time strings. TestPendingWorkflowRunDetailPreservesNullTimestamps directly checks both fields over HTTP. Build and full core/integration validation are logged per commit; the known Windows Git integration failure remains unchanged.
Create and link WorkflowRun/IssueRun atomically for Confirm and manual starts, bypass legacy dispatch, and enforce tenant-scoped one-to-one references in migration 0036. Settle all unlinked non-terminal history, retain editable terminal rows, and validate constraints on every database. Preserve the admission base live-form divergence gate verbatim. HTTP, concurrency, snapshot freeze and fresh/seeded migration regressions accompany this change; full core/integration and build checks are logged at this commit.
Project authoritative state in the caller transaction, write system activities and summaries, and preserve rollback/idempotency. Supplement run.started before direct terminal outcomes only with actual start evidence; awaiting_input leaves the IssueRun unchanged without rejecting the source transaction. PostgreSQL regressions cover these paths. Scheduler wiring remains deferred; full core/integration and build checks are logged at this commit.
Keep one interaction through confirm retries, show authoritative WorkflowRun status and link to its detail page. Historical rows without an invocation reference retain IssueRun status and have no run link. When the user selects a published version, load its snapshot form with issue context, render that version's fields, discard obsolete answers and retain the selected snapshot instead of the descriptor's newest-version default. Component/API regressions and bilingual module docs accompany the feature. The existing backend field-divergence gate stays unchanged; no polling or backend endpoint is added. The final rebased tree is validated with Go build, full core/integration packages and focused frontend gates. Race, per-commit rebuilds and HTTP/browser rechecks are explicitly excluded from this rebase follow-up.
Zpc001
left a comment
There was a problem hiding this comment.
Approve
006078ca6b667c2ce28fe4050bd0cd3421f5cfa9(基于含 #65 的 df507f0,无冲突,CI check / frontend 两项通过)。事务、迁移、投影三块我逐条核过,没有要改的地方;下面 5 条是接线与记录上的义务,建议合并前落到 PR 正文或对应 PR 里。
核过之后确认没问题的部分
- Confirm 的原子性:同一事务里
admitWorkflowRun→insertWorkflowRun→enqueueRunWithInvocation(ref 与 IssueRun 同一条 INSERT)→ interaction 的run_id IS NULL比较交换;insertWorkflowRun先于比较交换,所以 CAS 失败时 WorkflowRun 随事务一起回滚,不会留下无人引用的执行。TestWorkflowConfirmAdmissionRollsBackBothRuns把issue_runs/workflow_runs/issue_activities/ interactions 四样一起断言,TestWorkflowConfirmConcurrentInvocationCreatesExactlyOnePair断言 200+409 且各一张行,正好覆盖这条。 - 迁移顺序:先结算再上约束(否则 CHECK 加不上);
UNIQUE (workflow_invocation_ref)对非 workflow 行无影响(PG 允许多个 NULL);复合外键带tenant_id,租户一致性由 SQL 保证,与 ADR「一个 workflow IssueRun 恰好引用一个 WorkflowRun,一个 WorkflowRun 至多被一个 workflow IssueRun 引用」一致。deferred也在结算集合里是合理的——它只存在于0010_issue_collaboration.sql:59的 CHECK 与 OpenAPI 枚举,internal/core里没有任何写入者。升级测试用row_to_json逐行比对终态行与 agent 行未变,比我预期的严格。 - 投影函数:映射到既有状态词汇;
awaiting_input既不写 IssueRun 也不回滚调用方事务(TestWorkflowIssueProjectionAwaitingInputPreservesIssueRunAndCommits用commitWitness证明调用方的更新确实提交了);终态不可回退、不可改判;重放幂等(状态相同即早返回,整行与 activity 序列都比过);run.started的补写只在有started_at证据时发生,取消先于启动不伪造开始;run.message复用既有活动词汇,且issue_comments计数为 0,不冒充 workflow 评论;活动写入失败会把调用方的 workflow 状态一起回滚(TestWorkflowIssueProjectionActivityFailureRollsBack)。投影与状态转换同生共死,这是对的形状。 - 执行输入的切分是等价变换:
requireWorkflowRunInput只检查图声明的键、对未声明的键不做判定(internal/core/workflow_admission.go:61),所以 manual 路径把校验对象从整份 input 换成过滤后的 input 不改变判定;@路径的values已被validateFormValues(..., true)拒过未知键,过滤只去掉平台注入的repository/branch/prompt/context_refs。TestWorkflowConfirmFreezesHistoricalSchemaAndInput断言workflow_runs.input恰好是 Start 变量加全局变量,TestWorkflowConfirmValidatesAndExecutes断言 IssueRun 侧仍保留interactionValues.repository,两边都有痕。 - 不必重生成契约:
workflowInvocationRef本来就在internal/contract/openapi.go:148/:175的IssueRun定义里,api/openapi.json与frontend/src/api/generated.schemas.ts已含该字段且本 PR 未改它们,前端用的是生成客户端。workflowRunSummary的 null 时间戳修复也确认了(startedAt/finishedAt现在是原值直传,pending 运行返回null)。 - 前端:
useWorkflowSubmission把 interaction 的创建移进 mutation,失败时保留interactionId只解锁,一次编辑只有一个 interaction;历史行没有 ref 时useWorkflowRun的enabled为假,不会给每行发请求。
1(记录义务,非本 PR 引入)「按所选版本渲染表单」与 #65 的字段发散门禁互相抵消
confirmInteraction 仍然比较活稿描述符与所选版本描述符(workflowFieldDivergence,internal/core/workflow_collaboration.go:303,调用点在 issue_interactions.go 的 confirmInteraction)。前端这次改成渲染所选版本的字段,于是当所选版本的字段集合与活稿不同时,用户会看到该版本自己的表单、填好、确认,然后拿到 409 workflow_version_fields_changed——一个看得到却交不上去的表单。
这不是本 PR 引入的拒绝(改动前同样的选择也会被拒),生产行为没有回归;但本 PR 自己的 TestWorkflowConfirmFreezesHistoricalSchemaAndInput 也绕开了这个情形(注释原文"A newer graph with the same fields keeps the live-form compatibility gate satisfied"),也就是说这条路径没有证据。建议:把这条限制写进 PR 的"未包含 / 待对齐"与 #71 的验收说明,并明确跟进归属(这条门禁的规则目前不在 specs 里);若能顺手让前端把该 409 渲染成可操作的文案("该版本字段与活稿不一致,请先发布或另选版本"),比直接显示 fault 好。
2(小)isSnapshotSelector 用 key + type 判定,作者同名 select 会被误判
后端在作者自己声明 snapshotId 时不注入平台版本字段(workflow_collaboration.go:601-606),所以描述符里那个 snapshotId 字段是作者的。前端按 key === 'snapshotId' && type === 'select' 认定版本选择器,作者把它声明成 select(合法文档)时,前端会拿它的值去请求 GET …/snapshots/<作者的值>/form,404 后整个 composer 落到"表单不可用 + 重试"。测试里那一例是 text-input,所以没暴露。判定条件建议再加一层平台特征(例如选项值属于该 workflow 的快照列表),或由后端给平台字段一个稳定标记。
3(合并顺序)这份 PR 之后,没有人推进已确认的 workflow IssueRun
dispatchRun 对带 ref 的行直接返回(internal/core/issue_run_lifecycle.go:122-126),投影未接调度器,TestWorkflowConfirmValidatesAndExecutes 的期望从 run.enqueued/started/progress/message/completed 收成只剩 run.enqueued。这与 ADR「模拟 trace 不作为执行证据」一致,生产行为也不变(生产本来没有 dispatcher),作为 preflight 可以接受;但投影的调用点还没有归属:调度器在 #67 的 workflow_scheduler.go,而 #68 与 #72 也都在改这个文件。请在 #158 里写明"投影接进认领与结算"落在哪一份 PR,别让它随三份 PR 一起漂。
4(接线时)投影对时间戳的要求要传给调度器
projectWorkflowRunToIssueRun 在 running 时要求 started_at 非空、终态要求 finished_at 非空,否则 409 并把调用方的状态转换一起回滚。fail-closed 是好的选择,但它意味着调度器每次结算都必须先写时间戳,否则会陷入"结算被回滚 → 下一轮再来"。接线时请把这条写进调度器侧的测试。
5(记录义务)迁移遇到悬空引用会直接失败
复合外键是直接 ADD,若历史上存在指向不存在 WorkflowRun 的 workflow_invocation_ref,升级会失败。该列至今没有写入者(ADR 也是这么写的),现实中没有这种行,fail-closed 优于静默丢弃;建议在迁移注释里点一句"该列此前无写入者"。
Refs ora-space/circus#158
🤖 Generated with Claude Code
Move invocation linkage to migration 0037, reserving 0035 and 0036 for the earlier identity and execution work. Explain why the composite foreign key fails closed on unexpected dangling references. Identify the platform snapshot selector using all published snapshot ids from the existing paginated endpoint, preserving an author's same-named select as ordinary input when its options are custom. Explain how to resolve workflow_version_fields_changed in the composer without changing admission policy. Validation: Go build, the core package, all migration and invocation integration cases with a 30-minute timeout, and touched-file frontend format, lint, types, component/API and module gates. No scheduler or identity changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The two field-divergence tests repeated the same 409 handler, render and confirm steps, which the jscpd duplication gate rejects. Docs-Unchanged: test-only refactor; no behavior or module contract changed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep both README sections: main's session dashboard / model request statistics and this branch's workflow invocation linkage; list the 0035 model-attempt migration before 0037 in the migrations README. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reuse the real .orax, HTTPS marketplace and PostgreSQL harness to prove imported workflows enter the Issue target directory and their selected snapshot forms remain stable across administrators and import-trigger deactivation. Compare pending run bindings across those identities. Verify Confirm links its IssueRun to a WorkflowRun bound to the imported snapshot, direct starts select the same snapshot, and editing the draft cannot replace the frozen graph. After provider uninstall, preserve the old snapshot, publish a new version and create a run from it. Evidence stops at WorkflowRun creation and binding; real node execution remains with ora-space#70. No import implementation or specs changes. Validation: go build ./..., the core package, three new import invocation cases and 23 existing invocation/confirm/assets regressions with 30-minute timeouts. The merge has no overlap with this branch's frontend edits, so the conditional frontend gate does not apply. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… linkage Keep this branch's WorkflowRun linkage behaviour while adopting main's "Issue collaboration D9" citations in place of the removed migration notes, and list main's 0036 asset-import migration before 0037. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inkage main rebuilt docs/ and removed the accreted docs tree, so the invocation linkage notes move into docs/collaboration/interactions and docs/workflows/workflows. main also gained 0037_repository_bindings, and the persistence guide now requires a new migration to follow the latest number on main, so the invocation reference migration becomes 0038. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main gained 0038_agent_workspace_blocked_deadline, so the invocation reference migration moves to 0039 to keep following the latest number on main; the migration READMEs list main's 0038 before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EricWvi
left a comment
There was a problem hiding this comment.
main 已合入 cloud#85:docs/ 按领域整体重建为中英双语,文档地图在 docs/README.md,旧的 docs/*.md 已经全部删除。同时 cloud#62 已合入迁移 0038_agent_workspace_blocked_deadline.sql。请先合并或 rebase 最新 main,再做以下适配:
- 迁移编号:main 上最新的迁移已经是
0038。请把本 PR 新增的迁移顺延到合并时 main 最新编号之后,同步改测试里的文件名、测试名和升级基线,并在internal/core/migrations/README(.en).md末尾追加对应小节(两个文件现在和 main 冲突)。(本 PR 新增0038_workflow_invocation_reference)。 - 文档已经改在新的
docs/collaboration/和docs/workflows/下,很好;rebase 之后请确认改动没有被冲突覆盖。
|
@EricWvi 谢谢,已在 ecd2589 处理(合并最新 main
本地: |
Issue 协作文档仍把确认前的表单描述为始终取自当前文档,与前端选择已发布版本后重取快照表单的行为不符。 同步修正中英文说明,区分初次打开与选择快照后的表单来源,明确现有活稿字段差异 409 检查仍然生效,并在流程图显示关联创建的两类运行。 验证:对照 WorkflowInteractionComposer、useWorkflowSnapshotForm 和 confirmInteraction 的现有实现;两份文档的相对文件链接均有效;git diff --check 通过。 仅修改文档,不改变 API、字段差异门禁、迁移或调度行为。
|
@EricWvi 按本次 review 复核并补齐了文档,当前 head 为
本次只改两份文档。核对了现有前端和 Confirm 实现、相对文件链接, 本 PR 仍为 preflight:共用创建函数的身份/Project 与调度器状态同步等待 cloud#68/#72;fixtures=false 的真实 Node 联合验收等待 circus#70。这里请求复审本次文档与迁移适配,不表示这些剩余功能或总事项已完成。 |
合并 c6cccaf,适配已合入的运行身份、执行器槽位与真实会话执行。 direct、Confirm 与 manual 共用创建函数;后两者冻结实际调用者、Issue Project、插件版本和执行器绑定,缺 Project 时事务完整回滚,不使用开发模拟器伪造执行。 将尚未合入的调用引用迁移顺延到 0043,保留 main 的 0039–0042,并同步中英迁移与运行说明。 验证:真实 PostgreSQL 聚焦 core/integration 测试通过,无跳过;身份冻结、缺 Project 回滚和并发 Confirm 定向 race 通过;checkformat、task lint、diff --check 通过。 本次不包含调度器向 IssueRun 的状态投影调用和真实 Node 联合验收,PR 仍按 preflight 范围交付。
Zpc001
left a comment
There was a problem hiding this comment.
Approve
889a84d0426c4d5cd702031e2cc6ed9e59622279(基于含 #68/#72 的 main c6cccaf)。
- 迁移编号 0043 正确:接在 main 已有的 0042 之后,
internal/core/migrations/目录 max=42,无冲突;中英 README 的 0043 小节两版一致。 - 确认链路:
confirmInteraction→enqueueWorkflowInvocation→insertWorkflowRun(冻结 created_by/project_id/plugin_version)→freezeWorkflowRunExecutors→enqueueRunWithInvocation写workflow_invocation_ref。workflowInvocationInput只取 Start 变量 + 全局变量,freezeWorkflowSnapshot把workflowSnapshotId写进 IssueRun.input。三入口共用创建函数,缺 Project 409 回滚。 - 投影:
projectWorkflowRunToIssueRun在调用方事务内做状态映射 + 终态守卫,awaiting_input不改 IssueRun;dispatchRun跳过已关联的 workflow IssueRun,避免双份执行。 - 迁移 SQL:先结算历史无引用非终态行,再加租户一致复合外键 + 引用唯一 + 形状 CHECK,无条件 VALIDATE。
- 文档中英同步:
docs/collaboration/interactions、docs/workflows/workflows、internal/core与迁移目录的中英 README 均成对更新。 - CI(check + frontend)全绿。
非阻塞观察:投影尚未接入调度器(preflight 已知,PR 正文已写明),已确认的 workflow IssueRun 停在 queued;preflight 仍等 #70 的项目选择器。
保留既有提交历史,合并 upstream/main 的 ceb39bc 外部 Git 线路,解决中英文迁移 README 冲突。 保留已合入的 0043_external_git_line,将尚未合入的 WorkflowRun 调用引用迁移顺延为 0044,并同步升级测试常量与中英说明。 新主线没有改变 direct、Confirm、manual 的共用创建函数及 created_by/project_id/plugin_version 冻结语义;本次不改运行创建实现。 定向测试发现新主线路由漏传 SlotName,使具体槽位 PUT 被当成列表请求返回 405;恢复该字段,由已有身份冻结测试直接覆盖。 验证:真实 PostgreSQL 定向测试中9个顶层用例初次通过;恢复SlotName后仅重跑剩余身份冻结用例,confirm/manual均通过,0跳过。合并代码checkformat/lint通过,字段修复后路由文件格式及router包lint通过。已通过的其余用例未重复运行。 调度器向 IssueRun 投影调用、fixtures=false 真实 Node 联合验收仍未交付,本 PR 保持 preflight。
wanglongan587
left a comment
There was a problem hiding this comment.
审阅 commit:3914c49615e421a2bfd03f40c8179572a3aae3f1(base upstream/main ceb39bc,合并主线未改写历史)。CI 按此 head 复核:check pass(10m25s)、frontend pass。
按 @Zpc001 在 circus#158 分给我的四项(迁移编号与中英 README、共用创建函数的 project_id 语义、docs/ 中英成对与链接、PR 只装交付物且 preflight 未完成项如实列出)我逐项核过,这四项本身没有要改的地方。下面一条是按 circus 协议必须补的说明,另两条是建议。
需要补(阻塞)
PR 描述没有写 ADR 状态。 这个 PR 实现的是 specs decisions/cloud/workflow/0-cloud-side-scheduler-owns-workflow-execution.md(当前 approved)的 D3:三种入口共用启动函数、创建事务里冻结 created_by / project_id / plugin_version / 逐槽位绑定、workflow_invocation_ref 的租户一致复合外键 + 唯一引用 + CHECK、存量非终态 workflow IssueRun 的一次性结算——都是 D3 正文里逐条写明的义务。按 circus 的「ADR 状态跟着实现走」,产品 PR 描述要列出它实现的 ADR 路径,并逐份写明合并后是否已全部实现。请补一段,例如:
- 实现的 ADR:
decisions/cloud/workflow/0-cloud-side-scheduler-owns-workflow-execution.md(D3 的创建与引用部分),仓库ora-space/specs; - 未全部实现:调度器把 WorkflowRun 状态投影回 IssueRun 的调用点、
fixtures=false的真实 Node 联合验收仍未交付,ADR 保持approved,剩余部分由 circus#158 的后续提交 / circus#70 承接,本次不需要开把 ADR 改为implemented的 specs PR; - 不涉及的也写一句:
20261015-executor-slots-replace-agent-model-ids的槽位语义本次未改,20261016-asset-import-and-published-snapshots已是implemented,本次只补导入快照走@/ 直接运行的调用证据。
描述补完重新打 status:in-review 即可,我在新 head 上确认描述并复核四项目标后给结论。
建议(不阻塞)
1. SlotName 补的是主线缺陷,建议单独落。 我核了 upstream/main:internal/core/public.go:30-31 已声明 SlotName,但 internal/api/router/router.go 构造 PublicRequest 时没有赋值,于是 personalSlotMappingsPublic 走 require(r.Method == "GET", 405, "method_not_allowed") 分支——主线现在 PUT / DELETE /api/v1/me/executor-slot-mappings/:slot 是 405,用户设置执行器槽位是坏的。这里的补法正确,证据就是新增身份冻结用例里那次 HTTP PUT(经真实 router,不是直接调 core)。但它和 #158 的主题无关,而本 PR 是 preflight、合并要等 circus#70 关闭:建议另开一个只带这一行 + HTTP 覆盖的小 PR 先修主线,或者至少开一个 circus issue 记录这个缺陷,别让主线的修复挂在一个可能几周后才合并的 preflight PR 上。至少请 owner 知道主线当前是坏的。
2. projectWorkflowRunToIssueRun 接线时留意它的 require 会回滚调度器的状态推进。 函数里 require(len(message) <= 20000, 400, ...) 与 require(w != nil, 404, ...) 失败都会让 WorkflowRun 那一次结算整体回滚,即:摘要超长(生产输出不受这个上限约束)或运行的 WorkflowRun 被软删,会让运行永远结算不了。接线时建议由调用方截断/清洗摘要,只有真正的契约冲突才 fail-closed。现在没有调用点,不阻塞。
核过、没有问题的部分
- 迁移编号:head 里
0035–0043与upstream/main逐字相同,新增只有0044_workflow_invocation_reference.sql,无同号;中英文迁移 README 的 0044 小节一一对应(结算范围含running/deferred、租户一致复合外键、唯一引用、其他 executor 不得携带引用、无条件VALIDATE、证据指向integration/workflow_invocation_migration_test.go)。合并前再按当时 main 核一次编号即可,现在没有冲突。迁移本身我按workflow_issue_projection.go的投影和enqueueRunWithInvocation的写入点了对:issue_runs_workflow_invocation_shape要求的「非终态必须有引用、其他 executor 不得有引用」与唯一 INSERT 入口一致,没有第二条会产生无引用 workflow IssueRun 的路径(modeForType("workflow")是form,Task Mode 分支到不了)。 project_id语义:insertWorkflowRun对三个入口统一调resolveWorkflowRunProject;直接运行取r.Body.S("projectId")(路由白名单已在 main 上含projectId),Confirm/manual 在enqueueWorkflowInvocation里取issue.project_ref,因此确认人必须能打开该 Project 的 Space。空值 409workflow_run_project_required(沿用 cloud#68 的原因码,不新造),不存在/跨租户/归档按既有 404 口径,deleting409resource_unavailable,冻结的是行 id 而不是入参字符串。cloud#70 的项目选择器依赖的正是这条语义,两边一致。身份冻结用例覆盖 Confirm/manual 的created_by/project_id/plugin_version/ 槽位绑定,以及缺 Project 时 IssueRun、WorkflowRun、活动、interaction 认领的完整回滚。docs/:docs/collaboration/interactions、docs/workflows/workflows、internal/core/README、internal/core/migrations/README与两份前端模块 README 都是中英成对、内容对应;我按 head 的树逐个解析了改动文档里的相对链接,全部存在,#form-mode工作流/#端口issue-只拥有消费侧的契约及其英文锚点都在。没有新增文档,docs/README.md的地图不需要改。文档没有把未实现的投影写成已实现(internal/core/README与docs/workflows都写明调用点未接、IssueRun 仍queued)。- 交付物:37 个改动文件全是代码、测试、
docs/与各模块 README,没有计划、进度或实现日志;git diff --check干净。preflight 未完成项在「未包含 / 待对齐」里都如实写了(投影接线、Project 成为用户可见的创建要求、所选版本与活稿字段不一致仍被拒、fixtures=false的真实 Node 验收)。
…nto invocation linkage main gained 0044_model_attempt_workflow_run, so the invocation reference migration moves to 0045; the migration READMEs list main's 0044 before it. cloud#94 fixed the missing SlotName on main, so router.go now matches main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wanglongan587
left a comment
There was a problem hiding this comment.
结论:本次增量通过,暂不 Approve——等投影接线提交
审的 commit:1ae5e42967e77962b8cd87e9f1818114cb7654df(父提交 3914c49 是本 PR 上一版 head,另一父 7cf4cda 是当时的 upstream/main)。CI 按此 head:check pass(10m26s)、frontend pass(3m33s)。
上一轮我请求的阻塞项已经解决:PR 描述补上了「ADR 状态」一节。我按 specs cacbd19 核对,三条声明都成立——根决策 decisions/cloud/workflow/0-cloud-side-scheduler-owns-workflow-execution.md 仍是 approved,本 PR 实现的是它 D3 的创建与引用部分;20261015-executor-slots-replace-agent-model-ids.md 仍是 approved,本次未改槽位语义;20261016-asset-import-and-published-snapshots.md 已是 implemented,本次只补调用证据。本次不开改 implemented 的 specs PR 是对的。
本次增量没有要改的代码
1ae5e42的合并分辨率只动了四处:迁移改名0044→0045、中英迁移 README 的 0045 小节、升级测试常量workflowInvocationMigration。PR 自有代码与上一版逐字相同(git diff 3914c49 1ae5e42 -- <本 PR 新增与修改的代码、测试、前端>为空),所以上一版对三入口共用创建函数、身份与 Project 冻结、迁移 SQL、投影函数与前端的逐条核对结论继续有效。- 迁移编号按
memory/rules/migration-numbering.md核过:upstream/main(4cc9c2d)最新为0044,本 PR 新增0045,无同号;0035–0044与 main 逐字相同(blob 一一比对);中英迁移 README 的 0044(main 的模型尝试登记)与 0045(本 PR)两节成对,0045 写明接在 0044 之后。 - 上一轮建议 1 已落实:
cloud#94(ed51486)在 main 上补回SlotName绑定,并新增TestExecutorSlotMappingHTTPBindsSlotPath,走真实 HTTP 覆盖 named-slotPUT/DELETE;本分支router.go与 main 相同,不再携带这处修改。 - 交付物:36 个改动文件全是代码、测试与正式文档,没有计划、进度或实现日志;
git diff --check干净;git grep未发现把调用引用迁移残留写成0044的引用。
为什么现在不能 Approve
不是这次提交有缺陷,而是本 PR 自己的「未包含」清单里还有一项属于本 PR 的义务:投影的调用点(作者已在 circus#158 说明正在做、会作为后续提交推到本 PR)。在这个 head 上合入会得到这样的用户可见结果:
projectWorkflowRunToIssueRun没有生产调用点(git grep只命中文档和测试):main 的调度器会推进 WorkflowRun,但关联的 IssueRun 永远停在queued;enqueueRun的pending_run_exists(internal/core/issue_run_lifecycle.go:81)对同一 issue、同一 workflow 的再次@返回 409,dispatchRun又在issue_run_lifecycle.go:122-126直接跳过带引用的行,于是运行做完了也开不了下一次;- 前端对这类行显示的是不再推进的
queued。
按 circus#158 里定下的顺序,把接线提交推上来后再打 status:in-review:
- 调度器在认领
pending→running成功之后、结算比较交换成功之后调用投影; - 调度器侧测试断言结算前先写
started_at/finished_at,否则投影 409 会把整次结算回滚(PR 正文已列这条义务); - 摘要由调用方截断到 20000 以内再传入,只让真正的契约冲突 fail-closed(上一轮建议 2)。
我在新 head 上确认这三点与 CI 后给 Approve,并在 circus#158 打 review:lgtm 时写明审过的 commit SHA。
一点提醒
main 在本 PR 合并 7cf4cda 之后又前进到 4cc9c2d(#61、#87),没有新增迁移,GitHub 仍报 MERGEABLE,不需要为此再合一次;最终合并前按当时的 main 再核一次迁移编号即可。
Refs ora-space/circus#158
Project only successful workflow status writes in the same transaction. Propagate settle CAS outcomes before session dispatch or cleanup, and truncate existing output/error summaries at UTF-8 boundaries within 20000 bytes. Add PostgreSQL coverage for Confirm lifecycle, repeat invocation after completion, deterministic failure, concurrent passes, lost CAS, summary limits, and atomic rollback. Validate with task format, go run ./cmd/checkformat, task lint, targeted DB tests, and the requested core/integration suite.
Keep Chinese and English workflow, collaboration, and core documentation aligned with same-transaction projection, affected-row guards, bounded summaries, and direct-run/awaiting-input no-ops.
main gained 0045_agent_configuration_catalog, so the invocation reference migration moves to 0046; the migration READMEs list main's 0045 before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wanglongan587
left a comment
There was a problem hiding this comment.
Approve — 投影接线三项满足
审的 commit:f8331354ed46a13a25da5f8edac2303ab87497de(base upstream/main 0f4e60b;本版两个提交 713b191 接线、fb34d82 文档,再合并 main)。
上一轮要求的三件事
- 调用点:
advanceWorkflowRun在认领pending→running的比较交换更新到行后调用projectWorkflowRunToIssueRun;settleWorkflowRunStates改为返回 affected rows,只有更新到行才投影。会话成功、失败、取消都经finishWorkflowRun→ settle,启动超时同理。CAS 没更新到行时finishWorkflowRun跳过 Workspace 清理、startWorkflowAgentSession不再入队会话工作项、commitWorkflowAgentTerminal的 cont 为 false,由下一轮按已提交状态重算。直接运行的开发模拟器分支同样只在更新到行后投影,@ 与 manual 不经过它。生产里所有UPDATE workflow_runs SET status都在这三处,没有第四条绕过投影的路径。 - 时间戳先写后投影:认领的同一 UPDATE 写
started_at,终态结算的同一 UPDATE 写finished_at,投影再校验(running要求startedAt非空、终态要求finishedAt非空)。TestWorkflowConfirmSchedulerProjectsRunningOnce/...CompletesAndAllowsNextInvocation断言 IssueRun 的started_at等于 WorkflowRun 的、completed_at等于finished_at,run.started只有一条,终态后同一 Issue 能再次 Confirm。 - 摘要截断在调用方:
workflowIssueOutputSummary从输出节点结果或运行错误生成,按 UTF-8 rune 边界截到 ≤20000 字节,两个调用点先截断再传入,投影里的 20000 守卫不再回滚结算。TestWorkflowSettleTruncatesIssueSummary覆盖超长 error 与超长 output 两种来源(19997–20000 字节、合法 UTF-8)。
本地复跑(PR head,真实 PostgreSQL 18,独立 schema)
go build ./...、go run ./cmd/checkformat通过。go test ./internal/core -run 'TestWorkflow':通过,含TestWorkflowAdvanceProjectsConcurrentPassesOnce、TestWorkflowSettleLostCASDoesNotProject、TestWorkflowSettleTruncatesIssueSummary、TestWorkflowAdvanceProjectionFailureRollsBackClaim。go test ./integration -run 'TestWorkflowConfirmScheduler|TestWorkflowInvocation|TestManualWorkflowInvocation|TestImportedWorkflow|TestWorkflowConfirm':通过,含三个新调度器投影用例。- CI 按此 head:
checkpass(10m59s)、frontendpass(3m41s)。
其他
- 迁移
0046接在 main 最新的0045之后,无同号;中英迁移 README 的 0045 / 0046 两节成对。合并前按当时的 main 再核一次编号即可。 - 相对 main 的 39 个改动文件全是代码、测试与正式文档,没有计划或进度记录;合并 main 没有改动 PR 自有代码(scheduler 相对 main 只有接线改动,session / lifecycle / core README / docs 亦然)。
- 文档中英成对,已从"调用点未接入、IssueRun 保持
queued"改为"实际状态更新成功后在同一事务投影"。 - preflight 未完成项(
fixtures=false真实 Node 联合验收)在描述里仍然如实列出;ADR 保持approved的声明成立。
非阻塞
workflowIssueOutputSummary 的 for !utf8.RuneStart(message[end]) 在"开头就是 20000 个以上续字节的非法 UTF-8"上会越界;现有来源(数据库 error 文本与 jsonText)不会出现,留作后续防御性写法即可。
Refs ora-space/circus#158
main gained migrations 0046-0048, so the invocation reference migration moves to 0049. enqueueRun keeps main's task-conversation admission checks and enqueueAdmittedRun, and both now insert through enqueueRunWithInvocation so the workflow invocation reference is written with the IssueRun. The IssueRun type keeps both workflowInvocationRef and main's triggerEvidenceRefId. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main replaced the core and migration READMEs with package and migration maps, so the invocation linkage moves into that format: the workflow*.go row names the shared WorkflowRun creation, the invocation reference and the IssueRun status projection, and the migration map gains 0049 with its settlement and constraint notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on linkage main gained 0049_thread_commands_workflow_run, so the invocation reference migration moves to 0050 in the migration map. main's new session end deadline settles through finishWorkflowRun, so it projects onto the linked IssueRun like every other status write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in cloud#91 (Node-unreachable settlement of in-flight workflow sessions), cloud#100, cloud#104 (workflow globals and sys.*) and cloud#105. The only textual conflict was the import block of workflow_scheduler_db_test.go; advanceWorkflowRun now takes the deployment's unreachability window, so the projection rollback test passes store.DeliveryUnreachableAfter like AdvanceWorkflowRunsOnce does. The new Node-unreachable settlement goes through finishWorkflowRun -> settleWorkflowRunStates, so it projects onto the linked IssueRun as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in cloud#83, cloud#101, cloud#102 and cloud#107. cloud#101 adds 0050_personal_agent_configurations.sql, so the invocation-reference migration moves on to 0051_workflow_invocation_reference.sql: the file is renamed unchanged, the integration test's migration constant follows it, and both migration READMEs list 0050 and 0051 in order. main's new `delete(input, "agentConfiguration")` lands in enqueueRunWithInvocation, the single writer that both enqueueAdmittedRun and the workflow confirm path go through. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in cloud#108 (workflow session turn deadline) and cloud#109 (workflow run cancellation). cloud#109 adds 0051_workflow_run_cancel.sql, so the invocation-reference migration moves on to 0052_workflow_invocation_reference.sql: the file is renamed unchanged, the integration test's migration constant follows it, and both migration READMEs list 0050, 0051 and 0052 in order. Every new settlement path (turn deadline, cancel-before-start, cancel of a running run) goes through finishWorkflowRun -> settleWorkflowRunStates, so each projects onto the linked IssueRun; a cancel before the claim projects queued -> cancelled without inventing a start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
新 head
@wanglongan587 @Zpc001 请按 🤖 Generated with Claude Code |
wanglongan587
left a comment
There was a problem hiding this comment.
复审 cloud#71 @ 08102c2:Request changes(迁移 README 文件数、PR 描述的过期陈述)
审过的 commit:08102c2f7b18c694fa4f0f8f27d0dafa83d9cf1d(增量范围 f8331354..08102c2;本 PR 最后一次合并的 main 为 08102c2^2 = 27e7f48,当前 upstream/main = b0ae8c7)。CI 按此 head:check pass(13m19s)、frontend pass(3m44s)。
上一轮之后的增量
- 迁移只改名:head 的
internal/core/migrations/0052_workflow_invocation_reference.sql与f8331354的0046_...sqlblob 完全相同(7229efe3f62870477b6d4606025d9e25c635f7bc);链路 0046→0049→0050→0051→0052,每次只改文件名;测试常量workflowInvocationMigration已同步。 - 投影接线与
f8331354审过的实现逐字一致;workflow_run.go少了startedAt/finishedAt的run.S(...)→run[...]补丁,是因为 main 的9e1e4fb(fix(core): keep unset workflow run timestamps null)已实现同一修复,本 PR 不再携带。 - PR 侧代码改动只有一处测试适配:
internal/core/workflow_scheduler_db_test.go的advanceWorkflowRun(tx, s.workflowRun, store.DeliveryUnreachableAfter);issue_run_lifecycle.go的合并冲突解决把本 PR 的enqueueRunWithInvocation接到 main 新增的enqueueRun→enqueueAdmittedRun链上,main 的任务会话准入保留;前端types.ts同时保留workflowInvocationRef与triggerEvidenceRefId。 - 其余有 patch 文本差异的文件,差别都来自 main 的上下文/行号(逐文件比对增删行一致),文档与前端代码本身没有新改动。
核对通过
- 迁移编号:head 最高 0052,main(
b0ae8c7)仍以0051_workflow_run_cancel.sql为最高,无同号;27e7f48..b0ae8c7的 8 个 main commit 没有新增迁移,也没有触及本 PR 的 39 个文件,PR 仍MERGEABLE。另三个开放 PR(#111/#106/#74)也还挂着 0051,先合者会占 0052 及之后,合并前仍按memory/rules/migration-numbering.md复核。 - 迁移 README 顺序:zh/en 的 0052 表行与 bullet 都紧随 0051,两语言一一对应;bullet 的结算、复合外键、唯一引用、CHECK、无条件 VALIDATE 与 SQL 逐条对应。
- 模块 README 与文档:
internal/core/README(.en).md的workflow*.go一行已按 main 重建后的代码地图格式改写,链接目标存在;12 个改动文档 zh/en 成对、锚点可解析,旧的「工作流 IssueRun 保持 queued」等说法已更新。 - 状态投影:认领 CAS 成功后(
workflow_scheduler.go:494-498)投影;settleWorkflowRunStates返回 affected rows,只有更新到行才投影(:623-648);main 新增的 Node 不可达、单轮超时、会话结束超时、取消(含开始前取消)都经finishWorkflowRun→ settle 投影;cancelWorkflowRunByUser只写cancel_requested_at,不改 status。开始前取消投影为queued→cancelled,因startedAt为空不会补写run.started(workflow_issue_projection.go:94);摘要由调用方按 UTF-8 截到 ≤20000 字节,正常结算不会因活动大小回滚。 - 三入口共用
insertWorkflowRun,Project 缺失统一 409workflow_run_project_required;Confirm/manual 走enqueueWorkflowInvocation冻结调用者与 Issue Project,直接启动取请求体;生产代码里workflow_runs.status的写点只有认领、结算、开发模拟器三处,都经投影。 - 交付物:39 个文件 = 1 迁移 + 9 Go + 10 Go 测试 + 7 前端 + 12 文档,无计划/进度/实现日志。
- ADR 状态:按 specs
6aad4f9核对,根决策0-cloud-side-scheduler-owns-workflow-execution.md仍approved、20261015-executor-slots-replace-agent-model-ids.md仍approved且本次未改槽位语义、20261016-asset-import-and-published-snapshots.md已是implemented;本 PR 只实现 D3 的创建/引用/投影,fixtures=false的真实 Node 联合验收未交付,保持approved、暂不开 specsimplementedPR 的判断成立。
需要修改(阻塞)
- 迁移 README 的文件数没更新。 head 的
internal/core/migrations/有 54 个.sql(main 53 个 + 本 PR 的 0052),但README.md:9仍写「当前共 53 个 SQL 文件。」、README.en.md:9仍写「There are currently 53 SQL files.」。请两语言一起改成 54。这正是 owner 在 circus#158 明确请 reviewer 核对的「迁移 README 的顺序与文件数」中的文件数一项。 - PR 描述有过期陈述(描述是 owner 合并判断的依据,请一并更新):
- 「改动」第 3 条:迁移「编号接在 main 已有的 0049 会话命令归属迁移之后」→ 实际前驱是
0051_workflow_run_cancel.sql(0049、0050 在中间)。 - 开头「preflight 仍未包含 …(等 circus#70)」与「ADR 状态」节「由 circus#158 的后续验收与 circus#70 承接」:circus#70 已于 2026-10-20T08:09Z 关闭,本运行已转
run,请改为由本运行的剩余验收 / #77 协调承接。 - 「未包含 / 待对齐」第 1 条写的是已交付的投影接线,请移到「改动」或改为已包含,避免和真正的未包含项混在一起。
- 「改动」的「修复:pending WorkflowRun 详情…」一条:main 的
9e1e4fb已实现同一修复,本 PR 的9e0fcb2与它重复(相对 main 已不产生 diff,对应集成测试仍在),请在描述里注明已被 main 吸收,或删掉这条,避免让人以为本 PR 还带这个实现。若愿意顺手清理,也可以在合入前把这个空提交从分支里去掉;不清理也不阻塞。
- 「改动」第 3 条:迁移「编号接在 main 已有的 0049 会话命令归属迁移之后」→ 实际前驱是
建议(非阻塞)
- 0052 的 bullet 可补一句它同时给
workflow_runs加了workflow_runs_id_tenant_uniq(复合外键的前置唯一约束)。 - 「三个入口共用创建函数」可点名
insertWorkflowRun(顶层createWorkflowRun只服务直接启动);docs/workflows/workflows(.en).md同一句也略宽。 workflowIssueOutputSummary里for !utf8.RuneStart(message[end])在开头就是 20000+ 续字节的非法 UTF-8 上会越界;现有来源不会出现,可留后续防御性写法。
改动后请在 circus#158 重新打 status:in-review,我在新 head 上复审。另:GitHub 的 reviewDecision 目前仍是 CHANGES_REQUESTED(EricWvi 2026-10-18 对 ecd2589 的 review),新 head 也需要一次覆盖它的审查;按 #158 13:05Z 的交接,后续开发由 @Zpc001 的接续运行承担,本结论只对 08102c2 成立。
补充:独立核验的非阻塞观察(不改变本次 Request changes 的两条)
以上四条不影响代码层结论:投影接入、CAS 语义、main 新增结算路径与共用创建函数都在 head 上成立;本次 Request changes 的两条(迁移 README 的文件数、PR 描述的过期陈述)是仅有的阻塞项。 |
The migration directory now holds 54 SQL files (main's 53 plus 0052), so both READMEs say so. The 0052 entry also names `workflow_runs_id_tenant_uniq`, the unique (id, tenant_id) constraint that the composite invocation foreign key requires. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@wanglongan587 两项阻塞都已处理,新 head
空提交 这是交接前我的最后一个提交,之后由 @Zpc001 的接续运行从 🤖 Generated with Claude Code |
wanglongan587
left a comment
There was a problem hiding this comment.
复审 cloud#71 @ 6699540:两项文档阻塞已解决;但 owner 的放宽结论还没落地,暂不给 lgtm
审的 commit:6699540325723d410aa8e98489f41bed18acf4d2(上一版 08102c2f7b18c694fa4f0f8f27d0dafa83d9cf1d,增量范围 08102c2..6699540)。按当前 upstream/main = ff72afa0d8dbebe77ec10231936221e17945c048 复核:最高迁移仍是 0051_workflow_run_cancel.sql,本 PR 的 0052 无同号;b0ae8c7..ff72afa 未触及本 PR 的迁移,GitHub 仍报 MERGEABLE / CLEAN。CI 按此 head:check、frontend 均 SUCCESS。
上一轮两条阻塞都已处理(已在 head 上核过)
- 迁移 README 文件数:
internal/core/migrations/README.md:9/README.en.md:9已改为「54 个 SQL 文件」;head 的目录里正好 54 个.sql(main 的 53 个 +0052_workflow_invocation_reference.sql),中英一致;顺带补在 0052 bullet 里的workflow_runs_id_tenant_uniq与 SQL 第 11 行对得上。 - PR 描述:迁移前驱改为
0051_workflow_run_cancel.sql;「等 / 由 circus#70 承接」改为 #70 已关闭、fixtures=false验收补做时与 #77 协调;已交付的投影接线移出「未包含 / 待对齐」;9e0fcb2注明被 main 的9e1e4fb吸收、相对 main 只多一个集成测试。Refs已指向接续运行 circus#374。
增量只有这两份 README(2 个文件、4 行),代码与上一轮审过的 08102c2 逐字相同,所以上一轮对迁移、投影接线、三入口共用创建函数、main 新增结算路径的核对结论继续有效。
现在不能 Approve:owner 13:35Z 的放宽结论未落地
@EricWvi 在 circus#158 13:35Z 的结论要求「Confirm 只按用户所选版本自身的字段校验启动输入,不再拿活稿比较,删除 workflow_version_fields_changed 这条门禁」。本 head 仍在拦:全仓唯一的生产调用点在 internal/core/issue_interactions.go:149-151,workflowFieldDivergence(liveFormDescriptor(...), versionDescriptor) 非空即 409 workflow_version_fields_changed。
需要按 owner 结论一起调整的地方:
- 后端:
issue_interactions.go:149-151;删除后workflow_collaboration.go:232的liveFormDescriptor、:303的workflowFieldDivergence没有其他生产调用点,可一并删除,workflow_collaboration_test.go:914的用例随之处理;workflow_collaboration.go:247、form_descriptor.go:325的注释也指向这条门禁。 - 集成测试:
integration/workflow_interaction_test.go:184的refusedFields与:997/:1018/:1039三处断言;按 owner 要求补「选字段与活稿不同的旧版本 Confirm,按旧 schema 通过」与「缺旧版本必填字段时按旧 schema 拒绝」。 - 前端:
frontend/src/features/issues/components/workflow-interaction-composer.tsx:51的 409 提示路径、workflow-interaction.test.tsx:245-248的用例,以及frontend/src/features/issues/components/README.md:36/README.en.md:36的「门禁保持不变」说明。 - 文档:
docs/collaboration/interactions.md:72-73与interactions.en.md:96-100把这条写成了行为,要改成按所选版本校验。 - PR 描述:「未包含 / 待对齐」第 2 条仍写「是否放宽由 owner 决定」,已过期,请改为按 owner 结论已放宽。
按 owner 的交接,这些由接续运行 circus#374 实现;实现后在新 head 上复审。本结论只针对尚未落地的 owner 结论,不是对 6699540 增量的否定——增量本身没有问题,只是它不能作为合并版本。
两条非阻塞(与 @creegon2 13:41Z 转给接续运行的一致)
0052_workflow_invocation_reference.sql:11的workflow_runs_id_tenant_uniq与 main0044_model_attempt_workflow_run.sql:18的workflow_run_tenant_identity重复(都是UNIQUE(id, tenant_id))。删掉后,6699540在 README 补的那句说明也要一起去掉。- 建议补一条 linked IssueRun 的端到端投影用例:Confirm 建出 linked IssueRun 后、下一轮调度前取消 → IssueRun
cancelled、started_at为 NULL、没有run.started;Node 不可达 →failed。
复审轨迹
f833135(Approve)、08102c2(Request changes:迁移 README 文件数、PR 描述)、6699540(本结论:增量通过,等 owner 结论落地后的新 head)。
Refs ora-space/circus#374(原运行 circus#158 已由作者归档)
|
说明:本 PR 由 cloud#114 接续(@Zpc001 在本分支最后一个提交 |
Refs ora-space/circus#374
Issue 里 @ Workflow 点 Confirm 时,按所选发布版本创建唯一的 WorkflowRun,并与 IssueRun 稳定关联;直接启动、manual workflow IssueRun 和 @ 确认走同一个创建函数;调度器推进 WorkflowRun 时,状态同步投影回关联的 IssueRun。已适配 main 上的运行身份与真实会话执行。circus#70 已关闭,fixtures=false 的真实 Node 联合验收仍未交付,补做时与 circus#77 的验收范围协调。
改动
issue_interactions.go、issue_runs.go、workflow_invocation.go):同一事务里依次做准入(admitWorkflowRun)→insertWorkflowRun建运行(snapshot_id取准入解析出的版本,input只放 Start 变量和全局变量)→ 冻结调用者的执行器槽位绑定 → 入队 IssueRun 并写workflow_invocation_ref→ 原有的run_id IS NULL比较交换。三个入口的共用创建函数统一冻结created_by、project_id、plugin_version。Confirm/manual 的创建人取已验证的调用者,Project 取 Issue 的project_ref;直接启动取请求体projectId。三种入口均要求合法可访问的 Project,缺失返回409 workflow_run_project_required。Confirm/manual 不通过开发模拟器伪造执行或跳过槽位绑定。issue_run_lifecycle.go),避免同一次调用出现两份互不相关的执行结果。TestWorkflowConfirmValidatesAndExecutes相应改为断言关联和 WorkflowRun 行。0052_workflow_invocation_reference.sql:先把没有引用、仍未终结的历史 workflow IssueRun 结算为 failed(workflow_execution_unavailable_before_invocation_linkage),再加(workflow_invocation_ref, tenant_id)→workflow_runs(id, tenant_id)复合外键、引用唯一、执行器类型与引用一致的 CHECK(历史终态行放行),无条件 VALIDATE。编号接在 main 已有的0051_workflow_run_cancel.sql之后;该列此前没有写入者,迁移注释里写明。projectWorkflowRunToIssueRun(workflow_issue_projection.go):在调用方事务里把 WorkflowRun 状态映射到 IssueRun(pending→queued、running→running、succeeded→completed、failed→failed、cancelled→cancelled),写run.started/run.message/ 终态 system activity,不冒充 workflow 评论;awaiting_input不改 IssueRun。workflow_scheduler.go、workflow_run_session.go、workflow_run.go):认领pending→running的比较交换成功后(同一 UPDATE 已写started_at)调用投影;settleWorkflowRunStates改为返回是否更新到行,只有更新到行才投影,终态结算同一 UPDATE 先写finished_at。会话完成、失败、启动超时、取消都经过这个结算。摘要由调用方workflowIssueOutputSummary从输出节点结果或运行错误生成,按 UTF-8 字符边界截到 ≤20000 字节,超长输出不会让结算回滚;只有契约冲突(执行器不一致、改写已终结的 IssueRun)才使整个事务回滚。行为变化:结算没有更新到行时,finishWorkflowRun不再做 Workspace 清理,会话节点不再在本轮继续推进下游,由下一轮按已提交状态重算。9e0fcb2(pending WorkflowRun 详情的空startedAt/finishedAt返回null)与 main 上 cloud#105 的9e1e4fb修的是同一件事,合并后相对 main 不再产生 diff;保留的只有integration/workflow_run_timestamp_test.go。SlotName的问题已由 cloud#94 在 main 上修复(带 HTTP 覆盖),本分支的router.go与 main 一致,不再单独携带这处修改。创建函数与已审过的冻结语义保持原实现。GET …/snapshots/:snapshotId/form重取该版本的表单;一次编辑只建一个 interaction,Confirm 失败重试复用它;已确认的行显示 WorkflowRun 状态并链接到运行详情,没有关联的历史行回退显示 IssueRun 状态;只有选项全是本 workflow 已发布快照时才把snapshotId字段当平台版本选择器(作者自己声明的同名字段不受影响);workflow_version_fields_changed显示为可操作的提示。docs/collaboration/interactions、docs/workflows/workflows(中英)、internal/core与迁移目录中英 README。测试
integration/workflow_invocation_test.go:未发布、跨 workflow / 跨租户 snapshot、非法输入都不留下任何行;选旧版本后编辑并重新发布,运行的 snapshot / input / definition 不变;同 Idempotency-Key 重放、换 key 409、并发两个 Confirm 只建一个 WorkflowRun 和一个 IssueRun;manual 路径同样关联;IssueRun.input.workflowSnapshotId与workflow_runs.snapshot_id一致。integration/workflow_invocation_migration_test.go:空库与带历史数据升级两种情况下约束都已 VALIDATE;四种非终态结算、三种终态保留、迁移重放、历史行之后仍可 UPDATE、新的无引用 workflow IssueRun 被拒。integration/workflow_invocation_identity_test.go:Confirm/manual 冻结实际调用者、Issue Project、插件版本与逐槽位模型绑定;后续配置变化不改写冻结值;开发模拟器不能使这两个入口跳过绑定或写出模拟执行结果;缺 Project 时两类运行、活动与交互认领均回滚。internal/core/workflow_scheduler_db_test.go、integration/workflow_invocation_test.go,真实 PostgreSQL):TestWorkflowConfirmSchedulerProjectsRunningOnce(认领后 IssueRunrunning、started_at与 WorkflowRun 一致、只有一条run.started)、TestWorkflowConfirmSchedulerCompletesAndAllowsNextInvocation(完成后 IssueRuncompleted、completed_at等于finished_at,同一 Issue 可再次 Confirm)、TestWorkflowConfirmSchedulerProjectsConditionFailure、TestWorkflowAdvanceProjectsConcurrentPassesOnce、TestWorkflowSettleLostCASDoesNotProject、TestWorkflowSettleTruncatesIssueSummary、TestWorkflowAdvanceProjectionFailureRollsBackClaim;直接运行仍不产生 Issue 活动。internal/core/workflow_issue_projection_test.go:状态映射、活动顺序、从 queued 直达终态补run.started、awaiting_input、重放。integration/workflow_run_timestamp_test.go:pending 运行详情的空时间戳。.orax+ HTTPS + PostgreSQL 工具,不 seed 数据):TestImportedWorkflowDirectoryAndRunsIgnoreImportTriggerUser:导入副本出现在@选择器目录,所选快照表单取自导入快照;换管理员、停用导入触发者后,目录、表单与运行结果不变。TestImportedWorkflowSnapshotBindsConfirmAndDirectRuns:@Confirm 与直接运行选导入快照,WorkflowRun 都绑定该snapshot_id;改活稿后再建运行仍冻结导入快照的图与输入。TestImportedWorkflowRemainsPublishableAndRunnableAfterUninstall:卸载插件后副本仍可读、旧快照逐字节不变,可以发布下一版本并用它建出运行。a302856:cloud#91/feat(core): record agent run cancellation requests #100/feat(core): declare and resolve workflow globals and sys.* variables #104/fix(core): keep unset workflow run timestamps null #105;8d1f3c7:cloud#83/feat(model-access): add personal Agent configurations and frozen run inputs #101/feat(model-gateway): support pinned Claude Messages requests #102/fix(core): omit the agent declaration association for undeclared plugins #107;08102c2:cloud#108/feat(core): cancel workflow runs by request and settle them at the scheduler #109)。cloud#101 占用 0050、cloud#109 占用 0051,调用引用迁移顺延为0052_workflow_invocation_reference.sql,文件内容不变;迁移 README 按 0050、0051、0052 排序。main 新增的结算路径——Node 不可达(cloud#91)、单轮超时(cloud#108)、开始前取消和运行中取消(cloud#109)——都经finishWorkflowRun→settleWorkflowRunStates结算,同样投影到关联 IssueRun;开始前取消投影为queued → cancelled,不补写run.started。advanceWorkflowRun新增的不可达窗口参数,在投影回滚测试里按生产传入store.DeliveryUnreachableAfter。验证:go build ./...、go vet、go run ./cmd/checkformat、task lint(0 issues)通过;前端完整npm run check通过(138 个文件、1160 个用例);带真实 PostgreSQL,internal/core的 Workflow/IssueRun 用例全过,integration 的 Migration/Workflow 用例 292 个通过,其中只有TestWorkflowAssetImportDoesNotFanOutToWorkspaces在机器高负载时报模拟 Nodenode_not_ready,单独重跑通过;它来自 main 的 cloud#83,本 PR 不涉及。上一轮合并(a302856)在真实 PostgreSQL 上跑完的 core 全量通过。140849f:cloud#95/fix(core): 工作流会话在初始回合结束后由调度器结束 #96/feat(core): expose WorkflowRun model attempt statistics reads #98/fix: pass the desktop default agent config through the publish gate #99,迁移顺延 0050;main 新增的会话结束超时经finishWorkflowRun结算,同样投影到关联 IssueRun):checkformat、task lint(0 issues)通过;前端完整npm run check通过;真实 PostgreSQL 上internal/core通过,integration 537 通过、5 跳过,失败的只有两个已知 Windows 专属 Git server 用例。credentialmaterial、credentialstore、gateway、gitpreset、gitserver、repoexec这几个包在 Windows 上测 Unix 文件权限、符号链接和 git 服务,本地失败;本 PR 对这些包没有任何改动,与 main 一致,以 CI 为准。ebb93cd,迁移顺延 0049;enqueueRun保留 main 的任务会话准入检查,enqueueAdmittedRun与它都经enqueueRunWithInvocation写入,前端 IssueRun 类型同时保留workflowInvocationRef与 main 的triggerEvidenceRefId):go build、checkformat、task lint(0 issues)通过;前端完整npm run check通过(0 clones、构建成功);真实 PostgreSQL 上 core + integration 1133 通过、5 跳过,失败的是两个已知 Windows 专属 Git server 用例,以及与本 PR 无关的插件计划用例TestStartPluginPlanSurvivesSelectionChangesAndExecutionFailures/unknown(与前端安装同时运行、机器负载高时超时,单独连跑 4 次均通过)。f833135:投影接线713b191、fb34d82,再合并 main 迁移顺延 0046):go build ./...、go run ./cmd/checkformat、task lint(0 issues)通过;带真实 PostgreSQL 跑go test ./internal/core/... ./integration:1083 通过、5 跳过、2 失败,失败的仍是已知 Windows 专属的两个 Git server 用例(git-http-backend.exe检测),与本改动无关。1ae5e42,迁移顺延 0045):go build ./...、go run ./cmd/checkformat、task lint(0 issues)通过;带真实 PostgreSQL 跑go test ./internal/core/... ./integration:1064 通过、5 跳过、2 失败,失败的是已知 Windows 专属的TestGitServerAuthorizesExecutorSyncFromCloudState、TestGitServerAuthorizesDeliveryPushFromCloudState(git-http-backend.exe检测),与本改动无关。REQUIRE_POSTGRES=1):10 个顶层定向用例已有通过结果,0 跳过,覆盖新 0044 的空库/升级、direct 创建、Confirm/manual 身份冻结、缺 Project 回滚与并发 Confirm。首次 9 个顶层用例通过,身份冻结用例暴露路由遗漏;补回SlotName后,仅重跑该用例的 confirm/manual 两个子例并通过,复用其余 9 项结果。合并代码的全仓 checkformat/lint 通过;恢复字段后只检查该路由文件格式和 router 包 lint,均通过。新提交的完整 CI 另行报告。889a84d(Windows、真实 PostgreSQL,REQUIRE_POSTGRES=1):聚焦go test ./internal/core ./integration通过,无失败或跳过;覆盖共享创建、Confirm/manual、导入快照、迁移与新增身份/Project 回滚场景。另对身份冻结、缺 Project 回滚、并发 Confirm 执行定向-race,全部通过;go run ./cmd/checkformat、task lint通过;该 head 的 CI check/frontend 均成功。这些结果仅对应旧版本,不代替此次 external-git-line 合并后的验证。go build ./...、./internal/core全过;Windows 全量 integration 曾因上游 Git 服务测试的git-http-backend.exe检测失败。前端触及文件的格式、lint、typecheck、测试与frontend:check:diff当时通过;这些历史结果不代替本次合并后的完整 CI。ADR 状态
ora-space/specs的decisions/cloud/workflow/0-cloud-side-scheduler-owns-workflow-execution.md(approved)D3 中的创建与引用部分:三种入口共用启动函数;创建事务里冻结created_by/project_id/plugin_version/ 逐槽位绑定;workflow_invocation_ref的租户一致复合外键、唯一引用与 CHECK;存量非终态 workflow IssueRun 的一次性结算。fixtures=false的真实 Node 联合验收仍未交付。ADR 保持approved,剩余部分由 circus#158 的接续运行承接(circus#70 已关闭),本次不开把 ADR 改为implemented的 specs PR。decisions/cloud/workflow/20261015-executor-slots-replace-agent-model-ids.md(approved)的槽位语义本次未改,只在创建时按既有语义冻结绑定;decisions/cloud/workflow/20261016-asset-import-and-published-snapshots.md已是implemented,本次只补导入快照经@Confirm 与直接运行的调用证据。未包含 / 待对齐
workflow_version_fields_changed(前端显示为"先发布活稿或另选版本")。所以 feat(core): bind @-workflow confirms to a real WorkflowRun of the chosen snapshot #71 验收"选旧 snapshot 用旧 schema"在字段不同的情形下做不到;这条门禁规则不在 specs 里,是否放宽由 owner 决定。🤖 Generated with Claude Code