Repository navigation
chore(fork): sync upstream multica v0.6.3 (CHE-1835, CHE-1837) [merge] - #296
Merged
Merged
Conversation
…ume replay (multica-ai#8549) * fix(execenv): exclude clean HEAD advances from resume replay * fix(execenv): normalize carried WIP before replaying local edits Co-authored-by: multica-agent <github@multica.ai> * fix(execenv): resume after conflicting local draft commits Co-authored-by: multica-agent <github@multica.ai> * fix(execenv): limit snapshot conflict handling to affected paths Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Sol-Boy <sol-boy@multica-ai.local> Co-authored-by: multica-agent <github@multica.ai>
…ipients (multica-ai#9242) * fix(inbox): restrict notifications to current workspace recipients Removing a member or leaving a workspace deletes their subscriptions, but several notification sources keep addressing the user by a retained ID: reactions to their issues and comments, retained assignments, explicit mentions, squad mentions through surviving squad-member rows, quick-create outcomes and children_done for a retained parent assignee. CreateInboxItem inserted those rows unconditionally and the inbox:new event was then sent to the user's own connections, so a former member could keep receiving new issue titles and comment content. Guard the shared insert instead of each source: a member recipient must still be a member of the item's workspace and an agent recipient must belong to it. An ineligible recipient yields no row (pgx.ErrNoRows), which every caller now treats as a quiet skip without publishing inbox:new or failing the underlying operation. The check runs in the statement's snapshot and takes no row locks; historical inbox rows are left untouched. Existing delivery tests created recipients without membership rows; their fixtures now add the membership the production path requires. * test(inbox): assert children_done settles receipts when the recipient left * refactor(inbox): centralize eligible notification writes Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: 千乘妍 (Xiaoyaner) <xiaoyaner0201@users.noreply.github.com> Co-authored-by: Sol-Boy <sol-boy@multica-ai.local> Co-authored-by: multica-agent <github@multica.ai>
…i#9249) * fix(realtime): revoke workspace access on membership removal Close removed members' sockets, revalidate registration, and gate captured write batches with fresh coalesced membership queries. Cover relay failure, replay, queue races, and transactional removal/rollback (MUL-8014). Co-authored-by: multica-agent <github@multica.ai> * fix(realtime): keep registration free of database waits Co-authored-by: multica-agent <github@multica.ai> * perf(realtime): narrow removal event prefilter Co-authored-by: multica-agent <github@multica.ai> * test(wakeup): avoid global backfill in workspace default test Co-authored-by: multica-agent <github@multica.ai> * fix(realtime): bound concurrent authorization and defer relay revocation Co-authored-by: multica-agent <github@multica.ai> * test(realtime): check caller budget without waiting for expiry Co-authored-by: multica-agent <github@multica.ai> * fix(realtime): decouple member-list invalidation from revocation Co-authored-by: multica-agent <github@multica.ai> * perf(realtime): skip removal decoding for member actor metadata Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Sol-Boy <sol-boy@multica-ai.local> Co-authored-by: multica-agent <github@multica.ai>
…overy feedback (multica-ai#8514) * fix(agents): recover completed builder drafts and align recovery feedback * fix(agents): reject array builder draft payloads
…t GC (multica-ai#7893) * fix(daemon): preserve tracked files during artifact GC * fix(daemon): close artifact GC Git preservation gaps Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: SSK <ssk@SSKs-Mac-Studio.local> Co-authored-by: Sol-Boy <sol-boy@multica-ai.local> Co-authored-by: multica-agent <github@multica.ai>
…ca-ai#9265) * fix(agents): persist builder draft warning dismissal Co-authored-by: multica-agent <github@multica.ai> * fix(agents): preserve builder warnings during automatic model cleanup Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Sol-Boy <sol-boy@multica-ai.local> Co-authored-by: multica-agent <github@multica.ai>
…ica-ai#9261) Arabic/Hebrew/Persian comments and descriptions that mix in English words, paths or numbers render left-aligned with scrambled word order, because every block inherits the page's LTR direction. Use `unicode-bidi: plaintext` so each paragraph, list item, heading and blockquote resolves its base direction from its own first strong character, and `text-align: start` so alignment follows it. Applied to .rich-text-editor (prose.css) and .markdown-content (markdown.css). LTR-only content resolves to LTR and is unchanged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… (ZIC-260) (multica-ai#8774) * fix(daemon): recover undelivered batch claims after request timeout Co-authored-by: multica-agent <github@multica.ai> * test(daemon): avoid copying task service locks in recovery fixture Co-authored-by: multica-agent <github@multica.ai> * test(tasks): isolate delegated recovery assertions (MUL-7658) Co-authored-by: multica-agent <github@multica.ai> * test(daemon): use one clock for deferred claim hints (MUL-7658) Co-authored-by: multica-agent <github@multica.ai> * fix(daemon): keep claim recovery within client deadlines (MUL-7658) Co-authored-by: multica-agent <github@multica.ai> * fix(execenv): preserve racy Git index timestamps in snapshots (MUL-7658) Co-authored-by: multica-agent <github@multica.ai> * fix(daemon): deliver claim responses before recovery side effects (MUL-7658) Co-authored-by: multica-agent <github@multica.ai> * fix(daemon): isolate HTTP claim retries from recovery (MUL-7658) Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: multica-agent <github@multica.ai> Co-authored-by: Sol-Boy <sol-boy@multica-ai.local>
…ca-ai#9274) * chore: clean historical comments (MUL-8034) Co-authored-by: multica-agent <github@multica.ai> * docs: preserve pending Composio expiry contract Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: multica-agent <github@multica.ai>
…ica-ai#9253) * feat(runtimes): price Claude Sonnet 5.5 and Haiku 5.5 * fix(runtimes): align Claude 5.5 metrics pricing (MUL-8018) Co-authored-by: multica-agent <github@multica.ai> * test(wecom): make inbox fallback timing deterministic (MUL-8018) Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: mika <mika@multica.magma-ads.com> Co-authored-by: Sol-Boy <sol-boy@multica-ai.local> Co-authored-by: multica-agent <github@multica.ai> Co-authored-by: yushen <ldnvnbl@gmail.com>
… log (multica-ai#9288) * MUL-8046: feat(issues): per-run cost bars and token detail in the run log The sidebar's cumulative spend curve becomes one bar per run with spend, token and agent-time totals, and each past run gains a second line with agent, duration or failure reason, tokens and model. The Runs dialog replaces the step curve with a bucketed bar chart (cost, tokens or agent time, stacked by agent or token type), adds a cost split by agent and model, model and token columns, and an expandable per-run breakdown. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * MUL-8046: feat(issues): one bar per run in the Runs dialog chart Time buckets spent most of the chart on hours where nothing ran and made each bar roughly one run anyway. The dialog chart now draws one bar per run like the sidebar strip: height is cost, tokens or agent time, colour is the agent or token type, a tick marks failed and cancelled runs, and day dividers replace the time axis. Drops the bucket, lane hit-testing and time-tick helpers. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * MUL-8046: fix(issues): split run bars by share so sub-dollar costs fill them Segments used dollar amounts as flex-grow; factors summing below 1 fill only that fraction of the free space, so bars and share bands under $1 drew short. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * MUL-8046: feat(issues): keep the cumulative cost chart as a second Runs dialog view Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
…ultica-ai#9291) Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
…tead of a welcome modal (multica-ai#9289) * MUL-8047: feat(onboarding): open the runtime guide issue directly instead of a welcome modal Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * MUL-8047: chore(onboarding): drop dead option cards, copy, and completion animations Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * MUL-8047: fix(onboarding): reopen the existing guide issue on duplicate A reload, or a create whose response was lost, leaves the guide issue from an earlier Skip in place while onboarding is still incomplete; the retry then hits the server's active-duplicate guard and the step was stuck toasting forever. Recover the existing issue from the validated 409 body and continue to completion. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
…ultica-ai#8814) * feat(workflows): workspace workflows with step handoffs (MUL-7420) A workflow is a named, workspace-level selection of statuses from the shared status catalog, in board order, with an optional handoff on each step. Projects opt in through project.workflow_id; a project without one keeps the whole catalog (the implicit Default workflow), so existing workspaces see no change. - issue_workflow table + project.workflow_id, CRUD API under /api/issue-workflows, POST /api/projects/{id}/workflow with a dry-run status mapping plan. Only issues on statuses the target workflow does not list are remapped, and remapping never hands issues off. - Issue writes keep the status inside the project's workflow. Entering a step with a handler through a status change assigns the issue to that handler and starts its run with the step's brief as the handoff note; an explicit assignee in the same write wins. Creating an issue starts at the workflow's starting step. - Task claims carry the issue's project workflow, and the brief renders a Project Workflow section so agents move along this project's statuses instead of the built-in ones. - Statuses a workflow lists cannot be archived. - Adoption is gated by the project_workflows_v1 flag; existing workflows keep working and projects can always switch back to Default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * feat(workflows): workflow settings, project picker and workflow-aware boards (MUL-7420) - Settings → Workflows (behind project_workflows_v1): the Default workflow plus named workflows, each shown as its step chain with handlers and the projects using it; an editor to pick statuses from the library, order them, mark the starting step, and set each step's handoff, instructions and next/back statuses. - Project Workflow property: switching dry-runs first and asks where issues on unlisted statuses go; nothing else moves and nothing is handed off. - A project board's columns are its workflow's steps, and each column head names who entering it hands the issue to. - Status pickers offer only the issue's workflow steps and say who each hands off to; boards refuse drops onto statuses the dragged card's workflow does not list. - New issues in a workflow project start on its starting step, with a hint naming who they will be handed to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * fix(workflows): name built-in steps once in the brief; roomier picker hints (MUL-7420) Built-in statuses have no stored name, so the handoff brief printed `todo` todo. Print the key alone when the name adds nothing. The status picker widens for workflow projects and shows the handoff as an arrow and name, so step names no longer truncate to one letter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * feat(workflows): handoff previews and a single timeline entry per handoff (MUL-7420) - GET /api/issues/{id}/workflow-handoff?status= says what moving an issue would do: who it goes to, which runs of its current agent are still active, and the brief the handler receives. Backs the confirmation. - POST /api/issue-workflows/preview-brief renders a step's brief from an unsaved workflow, for the editor's preview. - Mapping plans list the statuses that stay, so the switch dialog can say which issues are untouched. - A handoff is recorded on the status_changed activity (workflow, handler, whether a run started, the brief) instead of a separate assignee row. - The brief now reads like the one shown in the design: the workflow, the current step, its instructions, the statuses, and the commands to hand off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * feat(workflows): rebuild the workflow UI to the reviewed design (MUL-7420) The first cut used generic controls where the design had purpose-built ones. This brings every surface up to the mockup: - Settings → Workflows is one page: the workflows (step chain with handler avatars, handoff count, projects using it; Default first) and, below, the shared status library with each status's workflow usage. - The workflow editor is a full page instead of a dialog: draggable step cards summarising each handoff, and a panel for the selected step — swap its status, pick the handler with a segmented control and a searchable target, handoff instructions, next/back statuses, a preview of the brief the handler receives, duplicate and delete. - The project Workflow picker lists each workflow's statuses, handoffs and projects, links to settings, and always confirms the switch with what moves and what stays. - Moving an issue into a handoff step (status picker, table, board drop) asks first: who it goes from and to, a default-on option to stop the previous agent's run, and the brief. - Status pickers name the workflow and project, show each step's handler with an avatar or that the assignee stays, and explain themselves. - Boards: the handler chip in project column heads, hatched columns a dragged card cannot enter with the reason, and a drop hint naming who the card will go to. - The timeline records a handoff under its status change, with the brief the run received; the issue sidebar shows the workflow it follows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * fix(workflows): word a queued previous run as queued in the handoff confirm The confirm dialog said the previous agent was "still running (for N minutes)" even when its task had only been queued. Queued runs now read as queued, and the checkbox cancels them instead of stopping them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * feat(workflows): refuse a run's status change once the issue left its step A run decides where the issue goes next from the step it was queued for. When someone else moved the issue while the run worked, applying that decision undid their move: in the live Grok run, a PM parked NW-1 as blocked and the still-running agent moved it straight back to code review. Tasks now record the issue's status when they are queued (agent_task_queue.workflow_step, written by the task INSERTs; automatic retries keep their parent's step), and a run's own status changes move it along. In a workflow project, an agent status change from a run whose step no longer matches the issue is refused with 409 workflow_step_moved, naming where the issue is now and who moved it, so the agent stops instead of retrying. A handoff away from a squad now also stops the runs made on the squad's behalf, and stopped runs record who stopped them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * fix(workflows): keep every status entry point inside the issue's workflow The issue context menu listed every catalog status and applied handoff steps without the confirmation the status picker and board show, so a right-click could pick a status the workflow refuses or start an agent unasked. It now offers the workflow's steps and opens the handoff confirmation through a shared modal. One-click status actions no longer assume built-in statuses a workflow may not list: "mark done" lands on the workflow's done step (hidden when it has none), un-marking a duplicate returns to the workflow's start, and "mark duplicate" is offered only when the workflow lists cancelled. The batch toolbar offers a single project's workflow statuses when the selection sits in one project. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * fix(workflows): keep issue wakeups consistent with workflow steps Three places where project workflows and issue wakeups met: - A wakeup run is queued when it fires, so it took the issue's status at that moment as its workflow step. A wakeup an agent registered then bypassed the stale-step refusal: parked by a PM, the issue could be moved on by the agent's "check CI, then hand to review" wakeup. It now keeps the registering run's step; a member's wakeup still starts from the issue's status. - Retries carried handoff_note only for wakeup runs, so a retried workflow handoff lost its brief. Rows with a workflow step keep it. - Switching or editing a workflow remaps statuses in bulk without the close rule, so an issue remapped into a done status kept its wakeups and pending wakeup runs. The remap now ends them like any status write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * fix(wakeups): don't also wake the agent a write hands the issue to A workflow handoff or an assignment already starts the receiving agent's run. If that agent also subscribed an event wakeup to the issue's status or assignee, the same write queued a second run for one fact, and workflows made such writes frequent. The write now names the agent it hands the issue to in the transaction-local multica.handed_to_agent (the new agent assignee, a squad's leader, or a step's handler even when it already owned the issue), and wakeup capture skips that agent's subscriptions for the write's issue.* events. Other agents' wakeups, and task, comment and reaction events, are captured as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * feat(workflows): tell agents not to watch workflow issues with wakeups The handoff brief and the runtime's project workflow section now say that each step's handler gets a run when the issue enters the step, so wakeups on a workflow issue are for waiting on time or on something outside it, not on its status, assignee or runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * fix(workflows): refresh project usage after project changes Co-authored-by: multica-agent <github@multica.ai> * feat(workflows): MUL-7420 split columns from per-project handoffs Workflows now only define a board's columns between a fixed head (backlog, todo) and tail (blocked, done, cancelled). Handoffs move to project.workflow_handoffs, so projects can share columns and still hand off to different people. Default becomes a real, editable row that every project without a named workflow follows. Adds project handoff, add-column (project fork or shared) and project brief preview endpoints; same-agent adjacent columns re-run the agent. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * feat(core): MUL-7420 project handoffs and Default workflow client model Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * feat(views): MUL-7420 column-header handoffs and project workflow menu Board column headers set the project's handoff for that column; the project toolbar gets a workflow menu (full flow, switch, templates) and an add-column action. Views outside a project show Default's columns, with other statuses reachable through a status filter. Adds the issue flow card, create-project workflow choice, a columns-only workflow editor and a lighter status picker. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * fix(views): MUL-7420 wrap create-project workflow label in a menu group Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * feat(workflows): MUL-7420 keep workflow structure in settings; no squad handoffs Projects no longer add columns or create workflows: the add-column endpoint is removed and creating a workflow is admin-only. Handoffs go to one agent, a member or the project lead; squads route work themselves, so a handoff to one is rejected, as is the issue-creator handler. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * refactor(core): MUL-7420 drop the project add-column client Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * feat(views): MUL-7420 simpler handoff picker and workflow editor form The handoff form is one searchable "Hand to" picker (no handoff, the project lead, an agent or a member); the next status defaults to the next column and next/back overrides sit under "More options". The workflow editor gets labelled name and description fields and shows the fixed statuses as one start and one end row. Templates move from the project menu to Settings → Workflows → New, and the project board loses its add-column action. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * refactor(server): MUL-7420 keep handoffs on the workflow, make backlog and blocked optional Handoffs move back onto workflow steps: a workflow is the whole pipeline, and a project only picks one. The project lead stays a relative handler, so projects can still share a workflow. Handoff edits are admin-only, through the workflow write or PUT /api/issue-workflows/{id}/handoffs/{status}; the brief preview moves to the workflow too. Drops the unreleased project.workflow_handoffs migration. Todo, done and cancelled are required; backlog and blocked are optional and keep their fixed places. Without blocked, the brief points agents at the step's back status. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> Co-authored-by: Cursor <cursoragent@cursor.com> * feat(views): MUL-7420 edit handoffs on the workflow, optional backlog and blocked The workflow editor sets each column's handoff in its side panel, and Backlog and Blocked switch on and off. The board's column popover and the flow panel edit the workflow's handoff, say how many projects it reaches, and are read-only for non-admins. Drops the per-project handoff client code. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * fix(wakeups): MUL-7420 keep platform rules on writes that hand off nobody Migration 579 skips an issue.* event for the agent a write hands the issue to. Its filter compared agent_id with the transaction's handed_to_agent setting using IS DISTINCT FROM, which is false when both are NULL. Main's platform rules (child_done) have no agent_id, so every issue.* event that handed the issue to nobody was dropped for them: a parent leaving backlog never woke its agent for sub-issues that closed meanwhile (TestChildDoneHeldWhileParentInBacklog). Rules without an agent are never the handoff target, so they always capture. Extends TestHandoffDoesNotAlsoWakeTheHandler with a platform rule on a handoff and on a plain status change; the latter fails on the old filter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * feat(views): MUL-7420 three-way handoff choice; quieter move confirm The handoff form picks one of three directions, as in the mockup: no handoff, hand to an agent (starts a run), or hand to a member, project lead included (assignee only). What the step does, where it goes next and the back status only reach an agent's brief, so they show and save for agent handoffs alone. The board's move confirmation keeps the agent's brief collapsed. Create project shows the workflow picker even when Default is the only workflow, with a note on where to make more. The hidden-columns panel says a board's columns come from its workflow, with a link to manage workflows for admins. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * feat(workflows): confirm handoff on project move, per-project handoff copy, two-pane editor (MUL-7420) - A single issue moved into a workflow project from issue detail confirms the handoff of the column it lands on; the write opts in with enter_workflow_step. Batch, API and CLI moves stay administrative. - The handoff preview takes project_id to preview such a move. - Saving a shared workflow's handoff from a board can keep the change to that project: the server copies the workflow for it and switches the project in one transaction (copy_for_project_id). - The column popover says which workflow it edits and who else uses it. - The workflow editor is a step list with a detail panel for the selected step. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * style: gofmt workflow tests Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * feat(views): MUL-7420 show next/back always; edit workflow name and description in place Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * feat(views): MUL-7420 trim copy on the workflows settings page Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * fix: MUL-7420 keep pre-workflow behavior for workspaces that never adopt workflows The run step guard now applies only to workflows that hand off, and the standalone Statuses settings page keeps its original header. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * fix(views): MUL-7420 use a solid placeholder tone on the workflow header Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> * fix(workflows): keep the runtime brief cache-stable; fix project board and batch status gaps (MUL-7420) - Move the project workflow out of the runtime brief into the per-turn prompt so CLAUDE.md stays byte-identical across steps and issues. - An explicit status filter overrides the project workflow's columns; the hidden-columns panel lists statuses outside the workflow. - Batch status offers only statuses every selected workflow allows; a partial batch rolls back, refetches and warns. - setProjectWorkflow returns void instead of an unparsed body. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> Co-authored-by: Lambda <lambda@multica.ai> Co-authored-by: Cursor <cursoragent@cursor.com>
…ultica-ai#9294) Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
…nee or an observer (multica-ai#9293) - issueworkflow.Brief is the only renderer: the claim carries it into every run's per-turn prompt; the editor preview and timeline show the same text. - Workflow handoffs stop writing the brief into handoff_note, so a person's note no longer drops the brief and the handoff framing fits again. - Agents that are not the issue's assignee get an observer brief without the step's commands. - Clearer rule override and narrower wakeup guidance; user text is stripped of control characters. - multica-platform skill documents project workflows. Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
…ltica-ai#9292) Co-authored-by: multica-eve <273080382+multica-eve@users.noreply.github.com> Co-authored-by: multica-agent <github@multica.ai>
Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
Merge upstream tag v0.6.3 (peeled 18fa9f7) into fork main 2b13539. Conflict decisions: - onboarding shim routes: drop (upstream MUL-8047 deleted the handlers); keep fork RequireHumanActor on cli-token and desktop-token. - migrate cleanup map: add three issue_workflow index entries; drop the renumbered wakeup names the fork applies under its own names. - feature flags: keep fork keys, add ProjectWorkflowsV1. - run cost UI: take upstream redesign; reapply fork costYPercent guard in the cumulative chart. - issue activity row: upstream handoff block plus fork wakeup wrap, links and test ids (CHE-1726). - cmd_agent: keep fork runAgentEnvPatch. - comment-only conflicts (hermes_home, actor_guards): take upstream. - builtin skill issues.md: keep fork text, add project workflows bullet. - generated sqlc code regenerated with v1.31.1. - migrations lint: nine upstream/fork prefix pairs join allowedForkCollisions.
errcheck on realtime write deadline and close frame, gocritic filepathJoin in gc_test. No behavior change.
…departed member (CHE-1837)
…ark pings for departed members handled (CHE-1837)
…s instead of allow-listing collisions (CHE-1837)
added 2 commits
October 17, 2026 16:11
added 24 commits
October 18, 2026 08:18
…tep cancel races, duplicate-run step matching, parent project moves and the race helper (CHE-1837)
… across refreshes, cancel stale runs only while pending, match duplicate runs to the write, revalidate the parent project, scope the race helper (CHE-1837)
…ool cannot hang it (CHE-1837)
…ed status, Jev-routed squad receipts and create-time handlers (CHE-1837)
… stranded status, settle squad receipts only for the leader's run, resolve create-time handlers under the locks (CHE-1837)
…re its row loads (CHE-1837)
…te the editor on its loaded row (CHE-1837)
…step cancels and malformed handoff previews (CHE-1837)
…nly while the issue is still on the captured step, fail closed on malformed handoff previews (CHE-1837)
…656_dm_channel_default_off keeps its name (CHE-1837)
…cached previews, mapping selections and editor conflicts (CHE-1837)
…ff confirmations to the previewed state, keep mapping choices, gate cached previews and pin the conflicted editor version (CHE-1837)
…y state file (CHE-1837)
…t atomically (CHE-1837)
…de-peek status, run-confirm payloads, bound no-handoff previews and stop-run overlaps (CHE-1837)
…gain useUpdateIssue, preview call carries its project argument, catalogs awaited on workflows (CHE-1837)
…esult in the cached and malformed dialog suites (CHE-1837)
…ct catalog, carry status context and the handoff through every caller, bind no-handoff previews and cancel only the runs a handoff stopped (CHE-1837)
…lete catalogs and the mobile status write (CHE-1837)
…lve the workflow catalog authoritatively, and confirm mobile status changes (CHE-1837)
…(CHE-1837) # Conflicts: # packages/views/locales/en/settings.json # packages/views/locales/fr/settings.json # packages/views/locales/ja/settings.json # packages/views/locales/ko/settings.json # packages/views/locales/zh-Hans/settings.json
congvc-dev
marked this pull request as ready for review
October 19, 2026 18:05
congvc-bot-x99 Bot
pushed a commit
that referenced
this pull request
Oct 19, 2026
…7-666 (CHE-1795) main (PR #296, workflow catalog) now holds 657-666 under different names. The nine push migrations keep their order and content and move to 667-675; the concurrent-index cleanup map and the comments that name them follow. A fresh database migrates up through 675, and 675 down to 666 and up again.
This was referenced Oct 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Status: Draft. This PR syncs
cheese-work/multicawith upstream Multica release tagv0.6.3, following the release-tags-only decision (CHE-1054/CHE-1380). It is source integration only, not deployment approval. It stays draft until the dev team leader reconciles the independent different-lab review, OCR and current-head checks.Correction, round 11 (19 Oct 2026): Luna's signed review
01a152cf-5ec2-7499-b613-715f221a59b1on CHE-1835 reported three P1 blockers for head3222c5363c4da7333cef7653f2898bec02a70fedagainst base3ae6189563bbfe705d6baf1a0be0492969b7f510. This head fixes all three. Current head:1087097e649e732bb81c06508e19cd6a2646e8bd. Live forkmainis still3ae6189563bbfe705d6baf1a0be0492969b7f510: 0 behind. No merge was needed. The latest upstream stable tag is stillv0.6.3. Earlier OCR receipts and reviews cover older heads only. Full-range OCR stays NOT-RUN for this head. The 38 medium and 11 low OCR findings of the3222c5363report stay undispositioned. The 41 medium and 10 low findings of the earlier pair stay outside that receipt.Public contract (round 11):
POST /api/issues/batch-update:updates.handoff_previewis now enforced. A batch accepts only a null-handler binding ("no handoff"). Any other binding answers 400. A batch without the field behaves as before.updated_ids.updatedis unchanged.GET /api/issue-workflowsbody. It no longer reads it as an empty list.GET /api/issues/{id}/workflow-handoffand sends the existing optionalhandoff_preview. No server change.Round 11 blockers:
updated_ids. A partial result names the issue identifiers that stayed unchanged and offers a Retry that re-checks them. A catalog that cannot answer holds the write with a Retry toast. Sibling batch callers: priority and assignee batches never hand off. The run-confirm modal takes one issue for a status change. No CLI caller of batch-update exists.resolveIssueWorkflow. It is unresolved when a list is pending or failed, the project is missing from the project list, or the project names a workflow the workflow list lacks. It is resolved with no workflow only when the issue has no project, or when no workflow is stored and the project names none. The picker, the issue menu, the board drop, the batch toolbar and the create-form hint use it. A malformed workflow list now fails the query.useUpdateIssuerefuses a status write that has no binding. This is source and unit-test work only.Round 11 commits, in order:
78c1aa692(tests only, red) →1087097e6(fixes, green). No rebase, no force-push.Round 11 test-first evidence: CI at
78c1aa692failedfrontend-test,backend-tests, bothfrontend-views-testshards (run39211898020) andMobile Verify(run39211898067). Local red at that commit: core 7 failed, views 15 failed, mobile 1 failed (promise resolved "{ id: 'issue-1', revision: 2 }" instead of rejecting), GoTestBatchStatusRefusesAHandoffTheClientDidNotPreviewfailed (status = "in_progress", want "todo"andexpected 400, got 200). Disclosed repairs: three existing assertions inbatch-action-toolbar.handoff.test.tsxnow expect the null-handler binding (78c1aa692). In1087097e6,batch-action-toolbar.confirm.test.tsxmocks now keep the real module and expect the binding, one fixture inissue-actions-menu.test.tsxnow uses a project that names no workflow, and the unused empty-list fallback constant and its test were removed.apps/mobile/data/workflow-handoff.test.tsis retrospective.Round 11 gates on X99, tree
1087097e6:go build ./...,go vet ./internal/..., the fullinternal/handlersuite,internal/migrationsandcmd/serverpass.cmd/multicafails the same tests onorigin/mainin this runtime, so it is an environment limit.pnpm typecheckpasses 10 of 10 tasks.pnpm lintreports 0 errors. Core passes 2398 tests. Views pass 6508 tests. Mobile typecheck, lint and 251 tests pass. Migrations: upgrade from main (711 versions) to 721, no-op rerun, fresh schema 721, andpg_dumpschema diff of 0 lines. No migration file changed this round. CI at1087097e6: 16 successful, 5 skipped, 0 failed, 0 pending.Round 11 limits: Web single-issue and board writes that resolve to no handoff still send no binding, so the server hands the issue off after a workflow edit until the catalog refreshes. Other clients that call batch-update without
handoff_previewkeep the old behavior. Runtime reproduction of the reviewer's scenarios is NOT-RUN. No device, simulator or Maestro run was done for mobile. Windows and macOS tests are NOT-RUN.Correction, round 10 (19 Oct 2026): Luna's signed review
01a151ca-7b32-7d2a-adc1-3c958ce980a2on CHE-1835 reported six P1 findings for head7ff70f64b640f79f33c8833abc778537d5e9cc98against base3ae6189563bbfe705d6baf1a0be0492969b7f510. This head fixed all six. Head at round 10 (superseded):3222c5363c4da7333cef7653f2898bec02a70fed. Live forkmainis still3ae6189563bbfe705d6baf1a0be0492969b7f510: 0 behind, 57 ahead. No merge was needed. The latest upstream stable tag is stillv0.6.3. Earlier OCR receipts and reviews cover older heads only. Full-range OCR stays NOT-RUN for this head. The 41 medium and 10 low OCR findings stay undispositioned.Public contract: No HTTP change.
handoff_previewis unchanged and stays optional. A preview that found no handoff is now sent with a null handler. The server already refused that binding when a handler became resolvable, and a test now pins it. One internal SQL query changed:CancelAgentTaskByUsergains two optional parameters (unless_assignee_type,unless_assignee_id). Both null keeps the old behavior and takes no issue lock. The batch endpoint still ignoreshandoff_preview.Round 10 findings:
batch-action-toolbar.tsx): fixed. A batch status change that enters a handoff step opens one confirmation (BatchHandoffConfirmDialog). Each handing-off issue is written singly with its ownhandoff_previewand the stop choice. The other issues move in one batch call after the confirmation. Cancel, a pending or failed preview, and an unloaded workflow or project list write nothing. A preview failure offers a retry. Audit of batch writes: status (fixed). Assignee: an explicit assignee never hands off, and an agent assignee already confirms. Priority: no workflow effect. Delete: own dialog.board-view.tsx): fixed. A project card stays put until both the workflow list and the project list have loaded. A failed load stays blocked.issue-property-pills.tsx): fixed. The pills now passprojectIdandissue. Audit ofStatusPickercallers: table, issue detail and sub-issue rows already passed both. The batch toolbar has its own guard. The create modal has no issue yet.runConfirmIntentcarriesstop_previous_assignee_runsandhandoff_previewinto the promote intent, andRunConfirmModalwrites them, with or withoutsuppress_run. Closing that dialog writes nothing. Audit: the issue-detail hook and the table row are the only callers.handoff_preview_stale.issue.go, single and batch): fixed. The handoff records the previous assignee's active runs under the issue lock. After the commit it cancels only those runs. Each cancel is also conditional at the statement on the issue not belonging to the previous assignee again. A run that arrived after the commit stays. A hand-back keeps the run. Lock order: the cancel holds no other lock and reads the issue row FOR SHARE in its own statement, likeCancelStalePendingStepTask. The stale-step cancellation is unchanged.Commits, in order:
5f1eb0552(tests only, red) →f9c68d0b1(tests only: batch toolbar fixture repairs) →74818ed2b(tests only: three existing no-handoff assertions now expect the bound result) →3222c5363(fixes, green). No rebase, no force-push.Test-first evidence: CI at
5f1eb0552failedbackend-testsonTestHandoffStopLeavesWorkThatCameAfterTheCommit. All 4 cases failed, single and batch: "the run that started after the commit = "cancelled", want running" and "the run of the agent that owns the issue again = "cancelled", want queued". It also failed bothfrontend-views-testshards on 20 behavioral assertions: writes before confirmation, a missing binding, missing context and dropped fields.TestUpdateComment_GovernanceFlagOn_ProviderErrors_ResponseUnaffectedalso failed there; it is outside this diff and passed at the fix head. Green at3222c5363: 16 successful, 5 skipped by path filter, 0 failed. Two tests are green on the parent by design:TestNegativeHandoffPreviewIsBoundAtTheWrite(characterization) andTestStopPreviousRunWaitsForAnUncommittedHandBack(retrospective).Local gates on X99, tree
3222c5363:sqlc generateleaves the tree unchanged.go vet ./...passes.golangci-lintreports 0 issues. The fullinternal/handlersuite and the other Go packages pass.cmd/multicaandpkg/agentpass from a clean worktree with a clean environment.pnpm typecheck10/10,pnpm lint0 errors,pnpm build6/6. Frontend tests: core 2386, web 337, desktop 678, docs 16, ui-lab 46, views 6494. Migrations are unchanged: a database upgraded from3ae618956(711 versions) reaches 721, a rerun applies nothing, and its schema equals a fresh database.Limits: The mobile app has no workflow code, so its status writes can still hand off without this confirmation. Handoff members of a batch are written one by one, so a failure leaves a partial result. The toolbar reports it. Windows and macOS tests and rendered UI are NOT-RUN.
Base reconciliation and correction, round 9 (19 Oct 2026): Luna's return
01a1505a-2cc5-715b-bc88-f8e762076436on CHE-1835 was STOPPED/NOT-RUN because live forkmainhad moved. Candidate head before this round:b423fa51ec38eb3fdee69a9e41f39ebe71a152c9. Live forkmainat execution:3ae6189563bbfe705d6baf1a0be0492969b7f510(CHE-1848, #303), merged in. Current head:7ff70f64b640f79f33c8833abc778537d5e9cc98; divergence 0 behind, 53 ahead. The two commits after5d01ae14b(1dceec2f2,7ff70f64b) change onlyserver/pkg/agent/hermes_escaped_holder_unix_test.go(see the CI note in the round 9 gates). The latest upstream stable tag is stillv0.6.3(all semver tags listed). Migration numbers in the older round sections below are superseded: the nine workflow migrations are now657–665, and the fork-only write-tag migration is666_wakeup_handoff_write_tag. Public-contract change this round: optional request fieldhandoff_preview(see below), reported for fresh review. Earlier OCR receipts and reviews cover older heads only; full-range OCR stays NOT-RUN. The stopped OCR attempt's five P1 candidates were triaged by the author only; the independent verifier makes its own disposition.Correction, round 8 (18 Oct 2026): The signed review of head
7d7f362cbb96dcfeb32e8e7e1e25e0d526a57aa1reported three P1 findings (comment01a14f4f-3f5d-77b0-877f-f5f6da5a5f27on CHE-1835). This head fixes all three. Current head:b423fa51ec38eb3fdee69a9e41f39ebe71a152c9. Execution base: forkmain6b89a1764afb6418af873336c720bbc36bcb447e, unchanged; upstream's latest stable tag is stillv0.6.3. The earlier OCR receipts and reviews cover older heads only. Full-range OCR stays NOT-RUN for the reviewed head (423 of 431 paths plus manual inspection of the other eight). Public-contract changes in round 8: none added. The handoff preview client now throws on a malformed successful response (see below), which changes client behavior only.Correction, round 7 (18 Oct 2026): The signed review of head
f72ba4e0cfc805ed3a923bbda70017e8f3754cbareported two P1 findings, both in the workflow editor (comment01a14e27-ebaf-72f9-8dae-443927ccc013on CHE-1835). This head fixes both. Current head:7d7f362cbb96dcfeb32e8e7e1e25e0d526a57aa1. Execution base: forkmain6b89a1764afb6418af873336c720bbc36bcb447e, unchanged. The earlier OCR receipts and reviews cover older heads only. Full-range OCR stays NOT-RUN for the reviewed head (423 of 431 paths plus manual inspection of the other eight). Round 7 changes no server code and adds no contract change: the optionalexpected_version/versioncontract of round 6 is unchanged.Correction, round 6 (18 Oct 2026): The signed review of head
e8e2fe552a1f59381237aa9725a3b2e086343530reported four P1 findings (comment01a14d7e-4da3-76a0-9a60-850a1f70994bon CHE-1835). This head fixes all four. Current head:f72ba4e0cfc805ed3a923bbda70017e8f3754cba. Execution base: forkmain6b89a1764afb6418af873336c720bbc36bcb447e, unchanged since round 5. The earlier OCR receipts and reviews cover older heads only. Full-range OCR stays NOT-RUN for the reviewed head (419 of 427 paths plus manual inspection of the other eight). Fresh OCR and a fresh independent review are owned by the dev team coordinator.Public contract change (round 6):
PATCH /api/issue-workflows/{id}accepts an optionalexpected_version. Workflow responses gain aversionfield (updated_atat full precision). A request withoutexpected_versionbehaves as before. A request whose version is not the stored one gets 409workflow_changed_elsewhere. The TypeScript types and zod schema carry both as optional.Correction, round 5 (18 Oct 2026): The signed review of head
9c3ae7bcaa5e8bd1a773c924949fbed35fc7677ereported five P1 findings and a test-synchronization caveat (comment01a14c92-0177-7e42-8816-aa9cac0b199bon CHE-1835). This head fixes all of them. Current head:e8e2fe552a1f59381237aa9725a3b2e086343530. Execution base: forkmain6b89a1764afb6418af873336c720bbc36bcb447e(#298), merged in. The earlier OCR receipts and reviews cover older heads only. Full-range OCR stays NOT-RUN for the reviewed head (416 of 424 paths plus manual inspection of the other eight). Fresh OCR and a fresh independent review are owned by the dev team coordinator.Correction, round 4 (18 Oct 2026): The signed review of head
c46f297f7a4c8250f90f98e1bce1d141674a8f10reported five P1 findings (comment01a14beb-71ac-7801-bc41-ef1ab5d6b383on CHE-1835). This head fixes all five. Current head:9c3ae7bcaa5e8bd1a773c924949fbed35fc7677e. Execution base: forkmain7c1261d6ff775a889d8e0a46a8d43685f1c5544f(#277), merged in. The earlier OCR receipts and reviews cover older heads only. Full-range OCR stays NOT-RUN for the reviewed head (413 of 421 paths plus manual inspection of the other eight). Fresh OCR and a fresh independent review are owned by the dev team coordinator.Correction, round 3 (18 Oct 2026): The signed review of head
bcdf401416c5ea3d0ea261e9206b1cbe780c0b36reported five P1 findings (comment01a149de-f4a8-7c22-bb84-eeaf4e83564fon CHE-1835). This head fixes all five. Current head:c46f297f7a4c8250f90f98e1bce1d141674a8f10. Execution base: forkmain15a54e92da9848c80fec6c97577b3e0317a9041e(#254, #300), merged in. The earlier OCR receipts and reviews cover older heads only. Fresh full-range OCR and a fresh independent review are owned by the dev team coordinator.Correction, round 2 (17 Oct 2026): The signed review of head
746b0a99267a4448884b3c13a942c4702bee1833reported five P1 findings. This head fixes all five. Current head:bcdf401416c5ea3d0ea261e9206b1cbe780c0b36. Execution base: forkmaina48be61c3221b6e161508ae4ee06b415a55e55ef(#286), merged in. The earlier OCR receipts and reviews cover older heads only. Fresh full-range OCR and a fresh independent review are owned by the dev team coordinator.Pinned refs:
v0.6.3: annotated tag object61bf2402edf4a585f8356f9b68b03f9e1bdabafe, peeled to commit18fa9f728a9e25f2465df2789631edb2a75442ad. Also upstreammainat execution (17 Oct 2026, 08:40 ICT). No newer stable release existed then (v0.6.3is the highestv0.6.*tag).main2b135399996d8072c5a99deb88ef55edb62f49b4(after fix(migrations): renumber agent_task_queue_context to clear duplicate prefix 627 (CHE-1824) #290). Forkmainthen moved to6c92e0c6820c9ae3512a0b5b38ad701bc0089a1e(feat(execenv): pass the managed MCP config to agy as a per-task plugin (CHE-1821) #287, feat(chat): create a coalesced inbox record for DM replies (CHE-1793) [squash] #276); that head is merged in (second merge commit below).v0.6.2(7ab92d7622ecd81d179a8d83ae2dea74835a5069). Divergence before the merge: forkmain240 commits ahead, 18 commits behindv0.6.3. No other sync PR or branch was open.1fea916f3(merge ofv0.6.3) →2874e8b9b(merge of forkmain6c92e0c68) →783571348(untracks a stray draft file added by mistake in2874e8b9b). →29b3b1650(go-lint fixes in upstream-authored lines: fourerrcheckinrealtime/hub.goandmembership.go, onegocritic filepathJoinindaemon/gc_test.go; no behavior change). Merge commits only, no rebase, no force-push. Tests-only first commit: none (merge-only candidate).53e74d336(tests only, red) →dd338e4fe(fixes, green) →2703e4e49(merge of forkmaind4978e0c0, sqlc conflicts resolved by regeneration) →2bf873ea1(renumbers the nine upstream migrations) →746b0a992(sqlc regenerated after the renumber). Merge commits only, no rebase, no force-push.746b0a992: 0 commits behind forkmaind4978e0c0, 27 ahead.450080227(merge of forkmain3ae618956) →5a8f7e2c6(renumber the nine workflow migrations and the write-tag migration to657–666; test-first disposition below) →e5870fd15(tests only) →5d01ae14b(fixes). Merge commits only, no rebase, no force-push.65d9f3d9e(tests only, red) →ee86e7f14(fixes, green) →b423fa51e(types one test double; no behavior change). No merge was needed. Divergence atb423fa51e: 0 behind, 47 ahead. No rebase, no force-push.c81b526e9(tests only, red) →7d7f362cb(fixes, green). No merge was needed. Divergence at7d7f362cb: 0 behind, 44 ahead. No rebase, no force-push.c1a5fdcce(tests only, red) →f72ba4e0c(fixes, green). No merge was needed: forkmainstayed at6b89a1764. Divergence atf72ba4e0c: 0 behind, 42 ahead. No rebase, no force-push.4fc9bd7bb(merge of forkmain6b89a1764, no conflicts) →d3ea959b2(tests only, red) →be5f4e514(fixes) →e8e2fe552(test helper: own connections for the race helper). Merge commits only, no rebase, no force-push. Divergence ate8e2fe552: 0 commits behind forkmain6b89a1764, 40 ahead. CI atbe5f4e514timed out inbackend-testsbecause the new helper test took pool connections it then waited on;e8e2fe552fixes that.c8ae94c75(merge of forkmain7c1261d6f, no conflicts) →8374469cb(tests only, red) →9c3ae7bca(fixes, green). Merge commits only, no rebase, no force-push. Divergence at9c3ae7bca: 0 commits behind forkmain7c1261d6f, 36 ahead.91ee35cd2(merge of forkmain15a54e92d, no conflicts) →0cb70ad48(tests only, red) →c46f297f7(fixes, green). Merge commits only, no rebase, no force-push. Divergence atc46f297f7: 0 commits behind forkmain15a54e92d, 33 ahead.81c9ad282(merge of forkmaina48be61c3, no conflicts) →74c403bce(tests only, red) →bcdf40141(fixes, green). Merge commits only, no rebase, no force-push. Divergence atbcdf40141: 0 commits behind forkmaina48be61c3, 30 ahead.Conditions at merge time: A merge to
mainstartscd-qualification.yml, and its success triggerscd-deploy.yml, which deploys to C00 through thec00-productionenvironment. The same push builds a newmultica-daemon-<os>-<arch>artifact, and fork-built daemons auto-update to it (CHE-1580). Merging this PR is therefore a deployment-relevant decision.Related Issue
Closes CHE-1837
The PR title also carries CHE-1835, the sync issue this PR delivers. CHE-1835 stays open until review, OCR and the ready decision finish.
Changelog
Changelog: none
Type of Change
Changes Made
All 18 upstream commits after
v0.6.2merge in with a merge commit. Conflict decisions (17 conflicted files in thev0.6.3merge, 2 in themainmerge):Onboarding shim routes (
server/cmd/server/router.go): retain (round 3). Upstream MUL-8047 deleted the pre-v3 shim. The base fileonboarding_shim.goallows deletion only afterX-Client-Versiontelemetry shows every active install has aged out, and this PR has no such telemetry. The round 3 commit restores the two routes, the handlers, their tests,SetStarterContentStateand thestarter_content_statefield of the user response from forkmain. Retain the fork'sRequireHumanActoron/api/cli-tokenand/api/auth/desktop-token; upstream's plain/api/cli-tokenregistration is not taken.Migrations cleanup map (
server/cmd/migrate/main.go): add the three upstreamissue_workflowindex entries (574,576,582). Upstream's renumbered wakeup names are not added; the fork applies those under its own names.Feature flags (
featureflags/keys.go): retain all fork keys (Jev, receipts, wakeup definition writes, export privacy); add upstreamProjectWorkflowsV1.Run cost UI (
execution-log-section.tsx,issue-runs-dialog.tsx): adapt. Take the upstream redesign (cost bars, totals, per-agent chart). The fork's only delta there was thecostYPercentguard (non-finite or zeroyMax); it is reapplied inissue-runs-cumulative-chart.tsx, whereyPctwas still unguarded.costYPercentstays used bystepCurvePath.Issue activity row (
issue-detail.tsx): adapt. Upstream's nested row with the workflowTimelineHandoff, plus the fork's wakeup wrapping,WakeupActivityLinksand test ids (CHE-1726).Agent CLI (
cmd_agent.go): retain the fork'srunAgentEnvPatch.Comment-only conflicts (
hermes_home.go,actor_guards.go): take upstream's shorter comments; code is identical.Builtin skill (
multica-platform/references/issues.md): retain the fork text and add upstream's project-workflows bullet.Generated code:
server/pkg/db/generatedregenerated with sqlcv1.31.1, not hand-merged.Inbox insert (
queries/inbox.sql, second merge): upstreamCreateInboxItemnow inserts only when the recipient is a workspace member or agent; fork feat(chat): create a coalesced inbox record for DM replies (CHE-1793) [squash] #276 addschat_session_idandchat_message_id. Both kept: the guardedINSERT ... SELECT ... WHEREwith the two new columns. sqlc output regenerated. Callers that useinbox.CreateIfEligiblealready treat no rows asinserted=false.server/internal/decisiontx/ping.go(fork) calledCreateInboxItemdirectly, so a decision ping to a recipient who left the workspace returnedpgx.ErrNoRows. The ping was then never marked handled and the worker retried it every five seconds. Fixed indd338e4fe:NotifyPingnow usesinbox.CreateIfEligible. A departed recipient gets no inbox item, and the ping is still recorded as handled.Workflow handoff assignee (
server/internal/handler/issue.go): a status change that also edits the description or attachments takesupdateIssueAtomically. Its nullable-field refresh restored the old assignee, so the workflow-selected handler was lost in single and batch updates. Fixed indd338e4fe:withWorkflowAssigneemarks the assignee as supplied when a handoff chose it. It copies the map, because a batch shares one map across issues.Migration numbering: upstream adds nine migrations (
573–579,581,582) whose prefixes collide with fork migrations already applied. They are new to this fork, so no database has recorded them.2bf873ea1renumbers them to656–664in their original order. The SQL bytes are unchanged. No applied migration is renamed or rewritten,allowedForkCollisionsis identical to forkmain, and the three runner name-map entries follow the new names. Details and the next-sync caveat are inserver/cmd/migrate/README.md. The fork'scapture_issue_wakeup(latest definition:532) differs from upstream's579redefinition by one added predicate line, so662_wakeup_skip_handed_to_agentis safe to apply on top.Round 2: workflow decisions under locks (
issue_workflow_write.go,issue.go): single and batch writers that land an issue in a project take the shared status-catalog lock, then a key-share lock on the project row, then the issue row. They then decide the workflow again against the locked rows. A workflow edit holds the catalog lock exclusively. A project switch holds the project row for update. So a write either finishes first or sees the new workflow. A status the workflow no longer lists returns 400status_not_in_workflow. An agent step that a member moved first returns 409workflow_step_moved. A changed handler or handoff decision returns 409workflow_changed; a batch skips that issue.Round 2: queue eligibility (
service/issue_trigger.go,issue.go): a pending assignment run stamped for a step the issue has left no longer suppresses a handoff into the next step. The write cancels it and queues the run for the new step. The previous assignee's runs now stop before the enqueue decision, so a cancelled run cannot leave a cached no-run answer.Round 2: wakeups (
issue_workflow_entry.go): superseded by round 3 below.Round 2: copy name and veto notice:
projectCopyNameclamps the base to the room left, so workflowQAwith a 61-rune project title no longer panics.decisionVetoNoticeStepusesinbox.CreateIfEligible, so a notice for a former member is recorded handled with no inbox item and no retry. The otherCreateInboxItemcallers already useCreateIfEligible.Round 3: the issue's own project (
issue_workflow_write.go): every update now carries a workflow write, also for an issue in no project. After it locks the issue row,verifyrefuses the write with 409workflow_changedwhen the issue sits in another project than the one the write decided for. A batch skips that issue. The write never validates under one project and persists under another, and never moves the issue back. It does not take the new project's lock, because that would invert the lock order against a workflow switch.Round 3: duplicate-mark lock order (
issue.go): the write takes the project lock, then the duplicate-mark locks (both issue rows in id order), then verifies under the issue row lock. The issue row lock used to come first, which could deadlock two crossed duplicate marks.Round 3: create (
service/issue.go):IssueService.Createresolves the project once (its own or the parent's), then takes the shared status-catalog lock and the project key-share lock, and only then reads the workflow. Both locks stay until the insert, for built-in and custom statuses. A create that a switch or edit overtakes starts ontodo.Round 3: handoff delivery (migration
665_wakeup_handoff_write_tag,wakeup_actor.go,issue.go,issue_trigger.go): the capture no longer skips the handed agent's issue events. The write tags its receipts with a write id. After the direct run is enqueued,ConsumeHandoffWakeupReceiptsmarks that agent's receipts of this write handled. A stop, a cancelled request or a failed enqueue between commit and enqueue leaves the receipts pending, so the agent gets the change at least once. A dispatcher pass between commit and consume can deliver it twice. A receipt merged with earlier pending events is not consumed.Round 3: JEV routing (
squad_jev_routing.go): routing takes the catalog, project and issue locks in the same order as other issue writes. It moves a backlog or todo issue toin_progressonly when the project's workflow lists that status. Otherwise it dispatches the worker and keeps the status.Round 3: sibling status writers: the GitHub merge sync writes
done, and the task-failure reset and the runtime sweeper writetodo. Every valid workflow liststodo,doneandcancelled(issueworkflow.IsRequired), so these writers cannot leave the workflow. They are unchanged. JEV routing was the only system writer ofin_progress.Round 3: test change (
issue_duplicate_maintenance_test.go):TestConcurrentWriteDoesNotRestoreClearedMarknow also accepts a wait on the issue row lock query, because the write takes that lock beforeUpdateIssue. The assertion on the final mark is unchanged.Round 4: board drops (
packages/views/issues/components/board-view.tsx):handleDragEndnow judges the column the pointer is released over, before it reads the mirrored column. After allowed B and blocked C the mirror stayed in B, and a release over C moved the card to B or opened a handoff for B. A release over a column the card's workflow omits, or an archived column, now resets the board and shows thedrop_blockedtoast.Round 4: duplicate-run delivery (
issue_trigger.go,agent.sql): when the direct run loses the pending-task unique index,dispatchIssueRunreports delivery only if the run that holds the slot isqueued. A queued run reads the issue at claim. A dispatched run read it earlier, so the receipts of the write stay pending. New queryHasQueuedTaskForIssueAndAgent.Round 4: stale media-deferred runs (
agent.sql):ListStalePendingStepTasksnow also lists runs deferred behind channel media, the same set as the unique pending-task index.CancelStaleStepRunscancels them, so the run for the new step queues instead of deduplicating against a stale one. The only caller of the query isCancelStaleStepRuns.Round 4: builder draft recovery (
packages/views/agents/create/builder-workspace.tsx): an unclosed<agent_draft>block is recovered only from the final assistant reply. Older replies are read as closed blocks only. A superseded unclosed reply can no longer merge over configuration saved after it. An unclosed final reply that was never applied is still recovered.Round 4: source-context create lock order (
service/issue.go): the source issue (also the parent) is locked after the catalog and project locks. A workflow switch holds the project row and then remaps the project's issues, so the old order deadlocked the two. The project is read from the parent before the lock; a parent moved in that window gives the child its former project.Round 5: builder draft rollback (
builder-workspace.tsx): only replies newer than the applied one can be read as drafts. After closed A, recovered unclosed B and manual edits, a later plain, failed or invalid reply C no longer brings A back or autosaves it. A genuinely newer closed draft still applies.Round 5: workflow editor refresh (
workflow-editor-page.tsx, five locale files): the editor follows a refreshed baseline only while it is clean. With unsaved edits, anupdated_ator status-count refresh keeps them. If the refresh changed the workflow's content, the editor keeps the edits, shows an alert with "Load latest" and "Keep my edits", and holds Save until one is chosen, so Save cannot silently overwrite the other admin. A clean editor refreshes as before.Round 5: stale-step cancel (
agent.sql,task.go,issue_trigger.go): new queryCancelStalePendingStepTaskcancels a run only while it is still pending, assignment-level and stamped for another step.CancelStaleStepRunsuses it throughCancelTaskOptions.StaleStep, so a dispatched run that starts after selection stays. User cancellation of running work is a different path and is unchanged.Round 5: duplicate-run delivery (
agent.sql,issue_trigger.go):HasQueuedRunCarryingIssueWritereplacesHasQueuedTaskForIssueAndAgent. A queued duplicate counts only if it is assignment-level (no wakeup, no trigger comment), has the same reviewed head, and is stamped for the step the issue is in now; when that step hands off, a run without a step does not count. Otherwise the receipts stay pending.Round 5: parent project under lock (
service/issue.go): after the source issue is locked, a child that inherits the parent's project compares it with the locked parent. A parent moved in between returnssource_context_changed(409), so the client retries against the current project. The create never persists under the former project's workflow.Round 5: race helper (
issue_workflow_race_test.go,race_helper_test.go):raceUntilBlockednow records the competing transaction's backend and fires only when a backend is blocked by it (pg_blocking_pids), on its own connection.TestRaceHelperIgnoresAnUnrelatedLockWaiterproves an unrelated waiter cannot fire it. Final-state assertions of the existing tests are unchanged.Round 6: workflow lost update (
issue_workflow.go,workflow-editor-page.tsx,mutations.ts): the editor saves against the version it started from. The server comparesexpected_versionwith the stored workflow under the exclusive catalog lock and answers 409workflow_changed_elsewhereinstead of replacing a newer save. The editor then keeps the edits, shows the existing "Load latest" / "Keep my edits" choice, and "Keep my edits" saves against the refreshed version. A successful save writes the response into the list cache, so a quick second save names the new version.Round 6: board drop on a stranded status (
board-view.tsx): drag-over no longer refuses a return to the card's own column when the workflow omits that status, and drag-end treats a release over the card's own column as a drop where it started. The blocked-target and archived-column checks of round 4 are unchanged.Round 6: squad receipts (
squad.go,issue_trigger.go):enqueueSquadLeaderTaskOutcomereports whether the leader's run, a Jev-routed specialist's run, or nothing was queued. Only a leader run settles the leader's receipts.enqueueSquadLeaderTaskkeeps its bool for other callers.Round 6: create-time handler (
service/issue.go,issue.go,source_context.go,issue_workflow_entry.go):IssueCreateParams.HandoffResolverresolves and permission-checks the step's handler under the catalog and project locks, for the status the issue actually lands on. Its answer replaces the assignee from the early unlocked read. The HTTP create and the manual comment sub-issue create set it when the caller chose no assignee. Other service callers (channels, autopilot, Lark, quick-create) set none and behave as before; they never resolved a handler at create.Round 7: version bound to the accepted revision (
workflow-editor-page.tsx): the editor keeps the version its baseline and draft came from, and a save sends that one, not the latest row's. The baseline now re-seeds on a version change as well as anupdated_atchange, so two saves in one second no longer hide behind equalupdated_at. A dirty editor that receives a refresh with different content holds Save behind the existing "Load latest" / "Keep my edits" choice. The kept edits are saved against the version that was showing when the editor chose to keep them. A refresh that changes nothing the editor shows advances the token. A successful save adopts the response as the new baseline.Round 7: editor before its row loads (
workflow-editor-page.tsx,hooks.ts, five locale files): an existing workflow shows a loading state until its row is in the query, an error with Retry when the list fails to load with no data, and the existing not-found state when it is missing. Fields and Save are absent in those states,canSaverequires the row, andsavereturns early without a row. A new workflow is created as before.useIssueWorkflowsgainsisErrorandretry, both additive. The server still accepts tokenless writes for old clients.Round 8: editor draft during a save (
workflow-editor-page.tsx): the "adopt the next baseline" flag is gone. A successful save adopts its response as the baseline only if nothing was typed since the save began; edits made during the save stay, on top of the revision the server accepted, and the next save names the response's version. An unrelated refresh during a save leaves the draft alone, so a later stale-version, mapping-required or plain failure finds the draft intact. The editor's own save arriving through the list raises no alert. A response for another target is ignored.Round 8: stale-step cancel (
agent.sql):CancelStalePendingStepTasknow also reads the issue rowFOR SHAREin a CTE and cancels only while the issue's current status is still the step the request captured. A request that captured step B and resumes after the issue moved to step C, with C's run queued, cancels nothing. A move to C that is still uncommitted is waited for. The single caller isCancelStaleStepRuns; running-task protection, stale media-deferred replacement and user cancellation are unchanged. The statement now holds a share lock on the issue row for its duration.Round 8: malformed handoff preview (
schemas.ts,client.ts,handoff-confirm-dialog.tsx):handoffis now required in the preview schema, andpreviewWorkflowHandoffthrows instead of returning an empty no-handoff preview when a successful response is malformed. The dialog shows its existing error with a Retry button and does not callonConfirm. A validhandoff: falsestill applies without asking, and a valid handoff still asks.EMPTY_WORKFLOW_HANDOFF_PREVIEWis removed. The server always sendshandoff.Round 9: migrations (
server/migrations,cmd/migrate):mainadded the published656_dm_channel_default_off, which collided with the unmerged656_issue_workflow. Main's migration keeps its name. The nine workflow migrations moved up by one,656–664to657–665, and the write-tag migration moved from665to666. Old to new:656_issue_workflow→657_issue_workflow,657_issue_workflow_pkey_index→658_…,658_issue_workflow_primary_key→659_…,659_issue_workflow_workspace_name_index→660_…,660_project_workflow_id→661_…,661_agent_task_workflow_step→662_…,662_wakeup_skip_handed_to_agent→663_…,663_issue_workflow_is_default→664_…,664_issue_workflow_default_index→665_…,665_wakeup_handoff_write_tag→666_wakeup_handoff_write_tag. Up and down SQL bodies are unchanged except two comment lines in the fork-only666files that name the earlier migration. The three runner cleanup mappings (658,660,665), the README and one Go comment follow the new names.666still runs after thecapture_issue_wakeupredefinition in663. The allow-list andTestMigrationNumericPrefixesAreUniqueare unchanged (git diff origin/main -- server/internal/migrationsis empty). The next-sync caveat stands: delete the nine upstream workflow filenames if a sync re-adds them, and keep666after the re-addedcapture_issue_wakeup.Round 9, candidate 1 (confirmed, corrected): unresolved workflows read as "no workflow" (
hooks.ts,status-options.ts,status-picker.tsx,issue-actions-menu-items.tsx,board-view.tsx):useProjectWithWorkflowreturnsresolved, true for an issue with no project or once the project and workflow lists have loaded. The single-issue status picker and the status menu write nothing while it is false, and the board leaves a project card where it is. A failed load keeps them blocked. Audited and left unchanged: the project picker (a project move is administrative withoutenter_workflow_step), batch status editing (server preview), the create modal (no issue yet).Round 9, candidate 2 (confirmed, corrected): a confirmation not bound to the previewed state (
issue_workflow_write.go,issue.go,issue_move.go, the dialog and its four callers): the confirmation now sendshandoff_preview(the assignee and handler it showed). Under the issue-row lock the write compares it with the locked assignee and the resolved handler and answers 409handoff_preview_staleon a mismatch, stopping no run. Single updates and board moves carry it; the move endpoint allows the new field; batch ignores it. Absent, the write behaves as before. New public field; review requested.Round 9, candidate 3 (confirmed, corrected): mapping selections reset by parent renders (
workflow-mapping-dialog.tsx): a new plan starts from the suggestions. A change in the contents oftargetKeys, not its identity, keeps every choice that is still valid and replaces only one that left the list.Round 9, candidate 4 (confirmed, corrected): a cached non-handoff preview auto-applied (
handoff-confirm-dialog.tsx): only a preview fetched since this opening counts. It alone may apply the move on its own, fill the dialog or enable the confirm button. While the refresh is pending the dialog shows its spinner. A failed refresh shows the error with Retry and applies nothing. A refresh that finds a handoff asks first.Round 9, candidate 5 (confirmed, corrected): conflict, mapping dialog and catalog refresh (
workflow-editor-page.tsx): while a conflict is unresolved, a refresh that adds no content change no longer moves the accepted version, andsavereturns early with a toast on every path, including the mapping dialog's confirm. "Load latest" also closes a mapping dialog that was computed for the dropped draft.Fork-only behavior: before the correction, files the fork changed and upstream
v0.6.2→v0.6.3did not touch are byte-identical to forkmain(git diff origin/main HEADoutside the upstream file set shows onlymigrations_lint_test.go). This covers runtime update routing (CHE-1580), governance and auth guards. Files both sides changed were merged by git or by the decisions above. The correction adds two fork-authored behavior changes, both with a tests-first commit (see How to Test).How to Test
Test-First check: PASS for the correction. The first correction commit
53e74d336changes only tests. Against its parent29b3b1650these three tests fail on behavior (not on compilation):The next commit
dd338e4feadds the fix, and the same tests pass. The migration renumber has no new behavior test.TestMigrationNumericPrefixesAreUniqueis its gate, and it passes with an allow-list identical to forkmain.Round 9 Test-First check. The merge and renumber commits change no behavior. The renumber has its own red: after the merge,
TestMigrationNumericPrefixesAreUniquefails ("migrations 656_dm_channel_default_off and 656_issue_workflow share numeric prefix 656") and passes after the renumber, with the test and allow-list untouched.For the behavior fixes, commit
e5870fd15changes only tests. Its CI run failedbackend-tests, bothfrontend-views-testshards and the aggregate jobs. Behavioral failures:TestHandoffConfirmationIsBoundToWhatWasPreviewed(reassignment and handler-change cases); status menu, status picker and board tests that expect no write before the workflows resolve; dialog tests for a cached non-handoff preview (applied before the refresh; no Retry after a failed refresh); the editor test that saves the old draft from the mapping dialog; and the binding tests for the dialog, board, picker, project picker and modal. Three of the new tests were wrong in ways the red run did not show, and I corrected them after the fix without weakening an assertion: the mapping-dialog test never actually selected a destination (it used a click the select ignores), so its failure there was not the intended one and it is now red for the right reason (in_review: "todo"where"done"was chosen) when the fix is removed; the status-picker binding test could not find its row; and the dialog binding test clicked the confirm button while it was still disabled. The unrelated-by-design tests that pass before and after: the direct-write control cases, the second editor conflict test, and the "falls back to a valid destination" mapping test.Round 8 Test-First check: PASS. Commit
65d9f3d9echanges only tests. Against its parent7d7f362cbthese tests fail on behavior. Its CI run failedbackend-tests,frontend-test, bothfrontend-views-testshards andfrontend-build. Thefrontend-buildfailure is a TypeScript error in one of the new test files, a compile failure that I do not count as red evidence.The overlap test pauses the older cancellation behind the newer step's uncommitted move, queues the newer run in that transaction, then lets it commit. The dialog test runs the real client parser with only the network stubbed. Two test defects surfaced only after the fix and are corrected in
ee86e7f14andb423fa51e: the overlap test inserted the newer run before removing the older one (the pending-run index admits one per issue and agent), and one test double had a wrong type. Commitee86e7f14adds the fixes and the same tests pass. The existing schema test that expected a malformed preview to become "no handoff" was replaced, as the admission asked.Round 7 Test-First check: PASS. Commit
c81b526e9changes only tests. Against its parentf72ba4e0cthese tests fail on behavior. Its CI run failed infrontend-views-test (1/2)(and the aggregatefrontend); backend jobs passed because no server code is involved.The same-second tests give two versions the same
updated_atand different full-precisionversion. They also assert that nothing is saved before the editor chooses. Passing before and after, by design: the new-workflow create test, the not-found test, the successive-save test, the "load row then save" test and the "refresh that changed nothing" test. Commit7d7f362cbadds the fixes and the same tests pass. No existing test was changed.Round 6 Test-First check: PASS. Commit
c1a5fdccechanges only tests. Against its parente8e2fe552these tests fail on behavior. Its CI run failed inbackend-tests, bothfrontend-views-testshards andfrontend-build. Thefrontend-buildfailure is a TypeScript error (the tests name the newversionfield), a compile failure that is not counted as red evidence.Passing before and after, as intended:
TestUpdateIssueWorkflowWithoutAnExpectedVersionStillWrites(compatibility),TestCommentSubIssueResolvesTheStepHandlerUnderTheProjectLocks, the 409 alert test, and the clean-editor refresh. The version race test saves twice inside one second on purpose, becauseupdated_athas one-second resolution. Commitf72ba4e0cadds the fixes and the same tests pass. No existing test was changed this round.Round 5 Test-First check: PASS. Commit
d3ea959b2changes only tests. Against its parent4fc9bd7bbthese tests fail on behavior (not on compilation). Its CI run failed inbackend-tests,frontend-views-test (1/2)andfrontend-views-test (2/2).The cancel race test holds the dispatched-to-running update open in a competing transaction and waits until the cancel is blocked on it. The helper now identifies that block by
pg_blocking_pids.be5f4e514adds the fixes.e8e2fe552changes only the helper's connections. The same tests pass ate8e2fe552. The editor test file is new; the clean-editor test passed before and after, as intended.Round 4 Test-First check: PASS. Commit
8374469cbchanges only tests. Against its parentc8ae94c75these tests fail on behavior (not on compilation). Its CI run failed inbackend-testsandfrontend-views-test (2/2).The delivery test calls
dispatchIssueRunwith a queued, a dispatched or no run holding the slot, because a concurrent enqueue cannot be made deterministic in a test. The lock-order test holds the project row as a workflow switch does, starts the create, waits for it to block, and then remaps the source issue in the holding transaction; under the old order the database aborts one side. The board test drives the captured dnd-kit callbacks: start, over allowed B, over blocked C, end over C. Commit9c3ae7bcaadds the fixes and the same tests pass. I changed no existing test case this round; the helperraceUntilBlockedgained an optional hook that runs while the write is blocked.Round 3 Test-First check: PASS. Commit
0cb70ad48changes only tests. Against its parent91ee35cd2these tests fail on behavior (not on compilation). Its CI runbackend-testsfailed at the test step.The enqueue tests use a database trigger on
agent_task_queue: one records the pending receipts at insert time, one refuses the insert. The race tests hold the competing writer's transaction open and wait for a blocked backend, as in round 2. Commitc46f297f7adds the fixes and the same tests pass. The original pre-v3 onboarding tests return with the restored handlers.Round 2 Test-First check: PASS. Commit
74c403bcechanges only tests. Against its parent81c9ad282these tests fail on behavior (not on compilation). The first failure line of each is shown.The race tests hold the competing writer's transaction open, start the write, wait until a backend is blocked on a lock, and only then commit the competing writer. They do not depend on timing. The next commit
bcdf40141adds the fixes, and the same tests pass.Round 9 gates at
5d01ae14b, run on X99 against isolatedpgvector/pgvector:pg17andredis:8-alpinecontainers:main3ae618956migrates to 711 versions (last:656_dm_channel_default_off). This head upgrades it to 721, applying the nine workflow migrations and666. A rerun applies nothing. A fresh database also has 721 versions.pg_dump --schema-onlyof both is identical except the random\restricttoken.TestMigrationNumericPrefixesAreUniquepasses and the allow-list is unchanged.sqlc generateleaves the tree unchanged.go vet ./...passes.golangci-lint v2.13.2 --new-from-merge-base=origin/mainreports 0 issues.go test ./internal/handlerpasses (239 s) on the committed tree5d01ae14b(clean worktree status). The other 98 Go packages pass with-p 1(82ok, 16 without tests).cmd/multicaandpkg/agentpass from a clean worktree withscripts/go-test-with-agent-cli-guard.shandTMPDIRoutside/tmp(pkg/agentwith-p 2 -parallel 2).pnpm typecheck10/10,pnpm lint(0 errors) andpnpm build6/6 pass. Frontend tests at low host load (load average under 12): core 2386, web 337, desktop 678, docs 16, ui-lab 46 and views 6470 of 6470 (--maxWorkers=6) pass.5d01ae14b: the first attempt failedbackend-agent-testsonTestHermesBackendReportsTurnWhenEscapedDescendantHoldsPipeswithholder state "": EOF. Diagnosis: not a daemon fault. The test's holder process records its pid withos.WriteFile, which creates the file empty before it writes. The test waits for the file to exist, can read it in that window, and fails on the empty read. The test file is upstream's (MUL-5241) and identical to forkmain, so the race predates this PR. Fix, tests first:1dceec2f2addsTestReadEscapedHolderIdentityWaitsOutAnEmptyStateFile, which reproduces the exact CI message in a clean worktree;7ff70f64bmakes the holder publish by rename and the reader wait out an unparsable state until its existing budget runs out, then fail with the parse error. The budgets and both original assertions are unchanged. After the fix the two escaped-holder tests pass 30 of 30 runs, andpkg/agentpasses in full. CI at7ff70f64b: 16 successful, 5 skipped by path filter, 0 failed, 0 pending. No production code changed in these two commits.Round 8 gates at
b423fa51e, run on X99 against isolatedpgvector/pgvector:pg17andredis:8-alpinecontainers.b423fa51ediffers fromee86e7f14only in one test file's types, so the Go runs onee86e7f14apply to it (git diff ee86e7f14 b423fa51e -- serveris empty).main6b89a1764(710 versions) upgrades to 720. A rerun skips everything. A fresh database also has 720 versions.pg_dump --schema-onlyof both is identical except the random\restricttoken.TestMigrationNumericPrefixesAreUniquepasses andallowedForkCollisionsis unchanged.sqlc generateleaves the tree unchanged.go vet ./...passes.golangci-lint v2.13.2 --new-from-merge-base=origin/mainreports 0 issues.go test ./internal/handlerpasses (246 s) on the committed tree ofee86e7f14. The other 98 Go packages pass with-p 1(82ok, 16 without tests).cmd/multicaandpkg/agentpass from a clean worktree withscripts/go-test-with-agent-cli-guard.shandTMPDIRoutside/tmp(pkg/agentwith-p 2 -parallel 2).pnpm typecheck10/10,pnpm lint(0 errors) andpnpm build6/6 pass. Frontend tests: core 2386 of 2386, docs 16, ui-lab 46, web 337 and desktop 678 pass when run per package. Views passes 6447 of 6447 with--maxWorkers=6.pnpm testruns failed with 5 to 100 s timeouts across unrelated files in core, web, desktop and views while the host load average reached 150 to 650 from other tenants' processes. I did not raise a timeout. I waited for the load to fall below 20 and ran each package separately; those runs are the ones reported above. A full-parallel views run at load 135 also failed with timeouts and is not counted.b423fa51e: 16 successful, 5 skipped by path filter, 0 failed, 0 pending.Round 7 gates at
7d7f362cb, run on X99 against isolatedpgvector/pgvector:pg17andredis:8-alpinecontainers. The Go sources are identical to the previous head; the Go runs below were on this tree.main6b89a1764(710 versions) upgrades to 720. A rerun skips everything. A fresh database also has 720 versions.pg_dump --schema-onlyof both is identical except the random\restricttoken.TestMigrationNumericPrefixesAreUniquepasses andallowedForkCollisionsis unchanged.sqlc generateleaves the tree unchanged.go vet ./...passes.golangci-lint v2.13.2 --new-from-merge-base=origin/mainreports 0 issues.go test ./internal/handlerpasses (272 s). The other 98 Go packages pass with-p 1(82ok, 16 without tests).cmd/multicaandpkg/agentpass from a clean worktree withscripts/go-test-with-agent-cli-guard.shandTMPDIRoutside/tmp(pkg/agentwith-p 2 -parallel 2).pnpm typecheck10/10,pnpm lint(0 errors; warnings are in files this PR does not change) andpnpm build6/6 pass. Frontend tests: core 2379, docs 16, ui-lab 46, web 337 and desktop 678 pass. Views passes 6436 of 6437 in both a combined and a standalone run. The failure is the 5000 ms timeout oftable-view-editing"confirms a status change that would start an agent run" under host load (load average up to 168 during this round). The test takes 1.7 s alone and passes alone; it timed out the same way in rounds 4 and 6. I raised no timeout and do not count it as waived.7d7f362cb: 16 successful, 5 skipped by path filter, 0 failed, 0 pending.Round 6 gates at
f72ba4e0c, run on X99 against isolatedpgvector/pgvector:pg17andredis:8-alpinecontainers:main6b89a1764(710 versions) upgrades to 720. A rerun skips everything. A fresh database also has 720 versions.pg_dump --schema-onlyof both is identical except the random\restricttoken.TestMigrationNumericPrefixesAreUniquepasses andallowedForkCollisionsis unchanged.sqlc generate(v1.31.1) leaves the tree unchanged.go vet ./...passes.golangci-lint v2.13.2 --new-from-merge-base=origin/mainreports 0 issues.go test ./internal/handlerpasses (245 s). The other 98 Go packages pass with-p 1, exceptcmd/multica,pkg/agentand one flake.cmd/multicaandpkg/agentpass from a clean worktree withscripts/go-test-with-agent-cli-guard.shandTMPDIRoutside/tmp(pkg/agentwith-p 2 -parallel 2).internal/governance/receiptfailed one test in that run and passes in 2 of 3 isolated reruns here. The same package fails 1 of 6 isolated runs on unmodified forkmain6b89a1764. This PR does not touch it.pnpm typecheck10/10,pnpm lint7/7 andpnpm build6/6 pass. Frontend tests: core 2379, docs 16, ui-lab 46, web 337 and desktop 678 pass. Views: 6426 of 6427 in the combined run and 6425 of 6427 in a standalone run. The failures are 5000 ms timeouts under host load (load average 21 to 31):table-view-editing"confirms a status change that would start an agent run" in both runs, andautopilot-dialog.validation"clears the assignee error and submits once an agent is picked" in the second. Both files pass alone, twice. The first of them also timed out under load at earlier heads of this PR. I raised no timeout.f72ba4e0c: 16 successful, 5 skipped by path filter, 0 failed, 0 pending.Round 5 gates at
e8e2fe552, run on X99 against isolatedpgvector/pgvector:pg17andredis:8-alpinecontainers:main6b89a1764(710 versions) upgrades to 720. A rerun skips everything. A fresh database also has 720 versions.pg_dump --schema-onlyof both is identical except the random\restricttoken.TestMigrationNumericPrefixesAreUniquepasses andallowedForkCollisionsis unchanged.sqlc generate(v1.31.1) leaves the tree unchanged.go vet ./...passes.golangci-lint v2.13.2 --new-from-merge-base=origin/mainreports 0 issues.go test ./internal/handlerpasses (253 s) atbe5f4e514; the later commit changes only a test helper, and the targeted race and cancel tests pass ate8e2fe552. The other 98 Go packages pass with-p 1, exceptcmd/multicaandpkg/agent. Both pass from a clean worktree withscripts/go-test-with-agent-cli-guard.shandTMPDIRoutside/tmp(pkg/agentwith-p 2 -parallel 2).pnpm typecheck10/10,pnpm lint7/7 andpnpm build6/6 pass. Frontend tests: views 6421 of 6421 (495 files), core 2379, docs 16, ui-lab 46 pass. Web passes 337 of 337 and desktop 678 of 678 when run per package. In the combinedpnpm testrun one web test,text-contrast"product UI expresses text hierarchy with tokens, not transparency", timed out at 5000 ms under load; the file passes in the per-package run.go test ./internal/handlerate8e2fe552with a four-connection pool was not completed: two governance race tests failed only because my test URL carriedpool_max_conns, which those tests hand to a plain connection that rejects it. They pass with the plain URL.e8e2fe552: 16 successful, 5 skipped by path filter, 0 failed, 0 pending.Round 4 gates at
9c3ae7bca, run on X99 against isolatedpgvector/pgvector:pg17andredis:8-alpinecontainers:main7c1261d6f(710 versions) upgrades to 720. A rerun skips everything. A fresh database also has 720 versions.pg_dump --schema-onlyof both is identical except the random\restricttoken.TestMigrationNumericPrefixesAreUniquepasses andallowedForkCollisionsis unchanged.sqlc generate(v1.31.1) leaves the tree unchanged.go vet ./...passes.golangci-lint v2.13.2 --new-from-merge-base=origin/mainreports 0 issues.go test ./internal/handlerpasses (249 s). All 98 other packages exceptcmd/multicaandpkg/agentpass with-p 1(82ok, 16 without tests).cmd/multicafails only inside the agent task directory; from a clean worktree withscripts/go-test-with-agent-cli-guard.shandTMPDIRoutside/tmpit passes.pkg/agentfailed once onTestDimSessionLoadRetrySucceedsunder default parallelism and passes with-p 2 -parallel 2; the test passes alone 3 of 3.pnpm typecheck10/10,pnpm lint7/7 andpnpm build6/6 pass.pnpm check:ui-exportspasses.table-view-editing"confirms a status change that would start an agent run", a 5000 ms timeout under load in two full runs; the file passes alone. The same file timed out under load at earlier heads of this PR.9c3ae7bca: 16 successful, 5 skipped by path filter, 0 failed, 0 pending.Round 3 gates at
c46f297f7, run on X99 against isolatedpgvector/pgvector:pg17andredis:8-alpinecontainers:665_wakeup_handoff_write_tag. A database migrated with forkmain15a54e92d(710 versions) upgrades to 720: the nine renumbered migrations as656–664, then665. A rerun skips everything. A fresh database also has 720 versions.pg_dump --schema-onlyof both is identical except the random\restricttoken.TestMigrationNumericPrefixesAreUniquepasses andallowedForkCollisionsis unchanged.sqlc generate(v1.31.1) leaves the tree unchanged.go vet ./...passes.golangci-lint v2.13.2 --new-from-merge-base=origin/mainreports 0 issues.go test ./internal/handlerpasses (242 s).go test ./... -p 1on a freshly migrated database: every packageok, exceptcmd/multica,pkg/agent,internal/governance/receiptandinternal/service.cmd/multicafails only because the run sits inside the agent task directory; from a clean worktree withscripts/go-test-with-agent-cli-guard.shandTMPDIRoutside/tmpit passes, andpkg/agentandinternal/daemon/...pass the same way.internal/governance/receipt(two budget tests) andinternal/service(one source-context cleanup test) each failed once in the long run and passed on rerun in isolation;internal/servicepassed as a whole package. No failure touches the changed code.pnpm typecheck10/10 andpnpm lint7/7 pass.mainmerge), Windows and macOS tests, rendered UI.c46f297f7: 16 successful, 5 skipped by path filter, 0 failed, 0 pending.Round 2 gates at
bcdf40141, run on X99 against isolatedpgvector/pgvector:pg17andredis:8-alpinecontainers:maina48be61c3(710 versions) upgrades to 719. The nine renumbered migrations apply as656–664. A rerun skips everything. A fresh database also has 719 versions.pg_dump --schema-onlyof the upgraded and fresh databases is identical except the random\restricttoken.TestMigrationNumericPrefixesAreUniquepasses.sqlc generate(v1.31.1) leaves the tree unchanged.go vet ./...passes.golangci-lint v2.13.2 --new-from-merge-base=origin/mainreports 0 issues.go test ./... -p 1on a freshly migrated database:internal/handlerand every other packageok, exceptcmd/multica,internal/daemon/execenvandpkg/agent. Those three fail only because of the host: the agent task directory marker, and/tmp/.gitmaking the Cursor MCP tests collide. From a clean worktree withscripts/go-test-with-agent-cli-guard.shandTMPDIRoutside/tmp, all three pass (pkg/agentfailed once on a codex timing test and passed on rerun).execenvfails the same way on forkmaina48be61c3.pnpm typecheck10/10 andpnpm lint7/7 pass.mainmerge brings chat meter changes that CI covers), Windows and macOS tests, rendered UI.Earlier correction gates at
746b0a992, kept for the record:, run on X99 against isolatedpgvector/pgvector:pg17andredis:8-alpinecontainers:maind4978e0c0(710 versions) upgrades to 719 versions. The nine renumbered migrations apply as656–664. A rerun skips everything. A fresh database also has 719 versions.pg_dump --schema-onlyof the upgraded and fresh databases is identical (columns, indexes, function bodies), except the random\restricttoken.sqlc generate(v1.31.1) leaves the tree unchanged.go vet ./...passes.golangci-lint v2.13.2 --new-from-merge-base=origin/mainreports 0 issues.go test ./... -p 1on a freshly migrated database: all packagesok, exceptcmd/multicaandpkg/agent. Those two fail only inside the agent task directory (host environment). From a clean worktree outside it, withscripts/go-test-with-agent-cli-guard.sh, both pass (pkg/agentwith-p 2 -parallel 2).pnpm typecheck10/10 andpnpm lint7/7 pass.mainmerge brings frontend changes that fork CI covers), Windows and macOS tests, rendered UI.Earlier gates at
29b3b1650, kept for the record:Gates run on X99 at the earlier heads. Typecheck, lint, vet and the first full frontend/Go runs were at
1fea916f3; after the second merge I re-ran sqlc, vet, typecheck, the migration check, the full Go suite, and views and core tests at2874e8b9b(the later commit changes no code):pnpm typecheck: 10/10 tasks pass.pnpm lint: 7/7 tasks pass (0 errors, 22 views warnings from upstream code).go vet ./...passes.sqlc generate(v1.31.1) leaves the tree unchanged.inbox-filter-menu,issue-detailsource-context,table-view-editing,table-view-project-grouping) are 5000 ms timeouts or a teardownwindow is not definedunder load. The four files pass alone (152/152). A turbo-parallelpnpm testrun also showed one timeout in webtext-contrastand one in desktopscripts/package.test.mjs; both pass in the per-package rerun.pgvector/pgvector:pg17database: a database migrated with forkmain(708 versions, including fork650–652) upgrades to 717; the eight upstream migrations apply out of order (573–578,581,582;579was already recorded under the fork's name) and a rerun is a no-op. The upgraded and fresh 717-version databases match on column catalog, index definitions and function bodies (md5 ofpg_get_functiondef).scripts/go-test-with-agent-cli-guard.sh; regular packages-p 1,pkg/agent-p 2 -parallel 2) against the isolated Postgres and Redis, from a clean worktree outside the agent task directory: all packagesokat both heads. Load flakes seen once and passing on rerun:TestCursorBackgroundUncapturedDisabledToolWatchdog(text file busyon fork/exec) andTestTraecliDrainsNotificationsAfterPromptResponse(passes 2/2 alone and in a fullpkg/agentrerun). One environment effect:/tmp/.gitexists on X99, socursorProjectRoottreated/tmpas a project and threeTestPrepareCursorMcpConfig*tests collided on/tmp/.cursor/mcp.json. WithTMPDIRoutside/tmpthe package passes. The fork code is unchanged by this PR.git diff --checkpasses, except one trailing blank line in upstreampackages/views/workflows/templates.ts.golangci-lint v2.13.2 --new-from-merge-base=origin/main: first CI run reported the five issues above; after29b3b1650local run reports 0 issues. CI at29b3b1650: all checks pass or are path-filter skipped (backend-tests,go-lint,sqlc-check,frontend-*,mobile,Changelog line).Verification limits: Windows-only and macOS-only tests did not run; this fork has no Windows or macOS CI runner.
golangci-lintis left to CIgo-lint. No daemon was restarted and nothing was deployed. Rendered UI was not checked.Checklist
/tmp/.giteffect are recorded above)apps/docs/content/docs/developers/conventions.zh.mdx(NOT-RUN: upstream copy taken as-is)AI Disclosure
AI tool used: Multica Agent (Claude Code, x99-claude-sonnet)
Prompt / approach: Pin
v0.6.3, merge it onto forkmainwith a merge commit, resolve each conflict by retaining or adapting fork behavior, regenerate sqlc output and run the gates on X99. The independent different-lab review and OCR are dispatched by the dev team coordinator after publication.