Uh oh!
There was an error while loading. Please reload this page.
feat(runtime-host): bind ScheduledTasks to Connection identity - #4321
Conversation
me2seeks
left a comment
There was a problem hiding this comment.
Blocking compatibility issue: this PR declares epoch 84 for the ScheduledTask Connection-identity wire contract, while PR #4308 independently declares the same global epoch 84 for the sandbox-continuation wire contract. RUNTIME_HOST_COMPATIBILITY_EPOCH is a single Host/Client interoperability boundary, not a per-feature version. Both branches are based on the old 9249bf3 base and are currently conflicting with main (which is at epoch 83). Please rebase and either compose both closed-shape changes under one epoch-84 ledger entry if they are intended to ship together, or land one at 84 and bump the other to 85 after the first. The stale 78→79 explanation should be updated as part of the same repair. Until this is resolved, the meaning of epoch 84 depends on merge order and clients cannot be given a deterministic compatibility contract.
Uh oh!
There was an error while loading. Please reload this page.
0d82021 to
19065e0Compare
Astro-Han
left a comment
There was a problem hiding this comment.
Thanks — reviewed 435d1838 for substance. @me2seeks holds the open block on the epoch, so I've left that to their thread apart from one factual note at the end.
The problem is real and the fix is the right shape. Identifying an agent_run effect by slug alone means a deleted Connection's slug can be re-taken and a stored task then executes under a different account's credentials — a credential-confusion bug, not just a resolution bug. Freezing llmConnectionId + llmConnectionSlug + model, resolving by the immutable ID, and validating the stored slug and model before a Session or AgentRun exists is the correct authority: the ID is the identity and the slug becomes a consistency check rather than a lookup key.
Fail-closed for legacy rows is the right default here. Silently resolving a slug-only task to some Connection is exactly the behaviour being removed, and refusing to execute is recoverable by recreating the task, while running under the wrong credentials is not.
I checked the one thing that looked like it might contradict the description. normalizeExecution rejects a missing llmConnectionId outright, while the type marks it optional for legacy rows, so I expected editing a legacy task's title to fail. It doesn't: normalizeUpdateScheduledTaskInput only normalizes effect when the patch carries it (scheduled-task.ts:215), so non-effect edits never reach that check. The claim in the description holds.
Also confirmed the execution fingerprint covers the full identity rather than the slug, so recovery admission can't re-admit a task under a replacement Connection.
No findings from me on the implementation.
Evidence boundary: I read the effect contract, the normalizer paths, the coordinator's resolution and fingerprint, and the agent_run origin change; I did not run the suites and did not review the 476 lines of new tests in detail.
Factual note, not a verdict — that stays with @me2seeks: the description currently tells three different epoch stories (the English summary says 78 → 79, the Chinese summary says 88 and asks for a specific merge order, the code declares 89), while main is at 87. Worth collapsing to one when you next rebase. On the merge-order point specifically, I'd gently suggest this PR shouldn't need to reference another one at all — taking main + 1 and documenting only its own contract makes it mergeable on its own schedule, whichever lands first.
AI-assisted review: drafted with Maka; I verified the legacy-edit path, the normalizer boundaries, and the fingerprint contents against the branch source myself.
439933d to
b4ce460Comparetestikun
commented
Sep 2, 2026
@me2seeks@Astro-Han The compatibility-epoch finding is addressed in |
Astro-Han
left a comment
There was a problem hiding this comment.
Thanks for the rebase. The fix itself is still right: llmConnectionId frozen into the template, resolved through the existing resolveExecutionConnection bound path, legacy rows fail closed, and the two execution-host cases (delete, recreate same slug, assert no run) are the real regression. Core, storage, runtime and runtime-host suites are green locally on b4ce4607.
The epoch is not done, though. main moved twice since your rebase point: 93 is #3704's proxy credential contract and 94 is #4486's context_overflow contract, so this branch's 94 collides and the 93 line in the ledger describes a contract that is neither on main nor in this diff. The repo's own guard says so:
node scripts/protocol-epoch-check.mjs --base origin/main --head HEAD
Please rebase onto current main, take 95 (re-check right before merge, #4308 and #4386 are also on 95), keep only this PR's own line in the ledger, and describe only this contract in the body without referencing other PRs.
One behaviour regression came in with the create/update gate. #validateAgentRunEffect resolves the Connection on every create and update that carries an effect, and the dialog always sends the effect for non-legacy tasks. So a task whose Connection is temporarily disabled cannot have its title or schedule changed, which is the property we kept for legacy tasks last round. The gate also gives no guarantee at fire time, where #resolveAgentRunConnection already runs and is the authority. Dropping the gate and the beforeMutate parameter removes the regression and about sixty lines.
Smaller, take or leave: duplicating a legacy agent_run task surfaces as an invalid_frame protocol error rather than the identity-required copy, because scheduledTaskDuplicateSeed carries the locked effect into a create; agent-run-store.ts swaps hasExactKeys for a hand-rolled check at one site; scheduledTaskExecutionFingerprint re-implements what stableHash in @maka/runtime/request-shape already exports; the two effect! in the dialog are already narrowed by the early return.
Evidence boundary: static read of b4ce4607 against main92fa5281; core, storage, runtime-host and execution-host suites run locally; Playwright not run.
AI-assisted review: drafted with Maka; I verified the epoch state, the create/update gate path and the dialog's effect handling myself.
简体中文
感谢 rebase,修法本身没变、仍然正确,本地相关套件全绿。但 epoch 没处理完:rebase 之后 main 又走了两次 epoch(93 是 #3704,94 是 #4486),本分支的 94 撞号,且台账里 93 那条描述的契约既不在 main 也不在本 diff。请 rebase 到当前 main 取 95(合并前再确认一次,#4308、#4386 也在 95),台账只留自己一条,正文不引用其他 PR。另外新加的创建/更新期闸门带来一处回退:Connection 暂时不可用时非 legacy 任务连改标题都会被拒,而 fire 路径已是权威,建议删掉闸门和 beforeMutate 参数。其余是小项,可选。
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Generated-by: Codex
Generated-by: Codex
b4ce460 to
2763d05Comparetestikun
commented
Sep 3, 2026
Follow-up: review feedback is addressed in 2763d05. The branch is rebased onto current main with compatibility epoch 99, the create/update Connection pre-validation gate and beforeMutate were removed, and regression coverage was added for temporary Connection unavailability and delete/recreate slug reuse. All review threads are resolved and the CI test check is passing. Please take another look when convenient. |
me2seeks
left a comment
There was a problem hiding this comment.
Verified on 2763d05: my epoch block is resolved (guard reports 98 -> 99, ledger carries only this contract, no other open PR claims 99), the create/update gate regression is gone (#validateAgentRunEffect/beforeMutate removed, with a regression test proving updates succeed while the Connection is unresolvable), and the remaining nits are addressed (stableHash reused, effect! gone). Re-ran the affected suites locally: 58/58 green, including the two-UDS-Client slug-reuse race asserting no Session/AgentRun state survives a replaced identity. Fixes #3927 as specified. Approving and merging.
One non-blocking P3 for follow-up: duplicating a legacy slug-only agent_run task surfaces a raw invalid_frame protocol error instead of a friendly reselect prompt; consider filtering the locked effect in scheduledTaskDuplicateSeed.
Uh oh!
There was an error while loading. Please reload this page.
Two new system_note kinds and the reshaped lastRequestAnchor land in @maka/core's closed allowlists. A merge-base client handshakes on strict epoch equality and would then fail to decode the first transcript carrying them; the epoch moves so the pair refuses each other at the handshake (main is at 100 after apache#4321/apache#4508, so this lands as 101). Refs apache#4559 Generated-by: Claude Code Claude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J
Summary
Fixes#3927
Scheduled
agent_runeffects now freeze the complete execution identity:llmConnectionId + llmConnectionSlug + model. Fire-time resolution uses theimmutable Connection ID and validates the stored slug and model before a
Session or AgentRun is created or a provider effect is dispatched.
Legacy slug-only rows remain readable and editable for non-effect fields, but
fail closed at execution time until they are explicitly recreated with a
Connection identity. Deleting Connection A and recreating its slug as
Connection B therefore cannot run A's task under B's credentials.
The Runtime Host compatibility epoch is 99 for this closed ScheduledTask wire
shape.
Verification
git diff --checkpass.settledText,autoScroll, andtrailingAction; this change adds no new UI type errors.AI use
Tool(s) and scope: OpenAI Codex implemented the bounded Connection-identity
change, resolved the rebase conflict, and added regression coverage. The human
contributor remains responsible for review and submission.
Checklist
Does this PR entail a change in behavior?