Skip to content

TaskFlow: add managed child task execution#58939

Closed
mbelinky wants to merge 11 commits into
workspace/clawflow-repack-v1from
workspace/clawflow-run-task-in-flow
Closed

TaskFlow: add managed child task execution#58939
mbelinky wants to merge 11 commits into
workspace/clawflow-repack-v1from
workspace/clawflow-run-task-in-flow

Conversation

@mbelinky

@mbelinky mbelinky commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • let managed TaskFlows create child tasks under themselves
  • make cancellation sticky so orchestrators stop scheduling immediately
  • keep tasks as the units of work while TaskFlow manages the parent-job lifecycle above them

Stack

What This PR Does

This is the first execution layer on top of the restored TaskFlow substrate.

Before this PR, TaskFlow could exist as durable state, but a managed TaskFlow could not yet launch child tasks under itself in a first-class way.
After this PR, a managed TaskFlow can spawn child tasks, and cancellation behaves like a real parent-job cancel: mark stop intent first, then shut down active children, then settle the TaskFlow once those children finish.

This PR adds:

  • runTaskInFlow(...) / owner-scoped spawning for managed TaskFlows
  • sticky cancelRequestedAt semantics before child shutdown
  • finalization to cancelled once the last active child settles
  • denial of new child-task creation after cancel has been requested or the TaskFlow is already terminal

What This PR Does Not Do

  • no DAG scheduling
  • no branching or loop semantics
  • no plugin DSL
  • no public SDK seam yet

Tasks vs TaskFlow

  • Tasks still do the work
  • TaskFlow now actually manages multi-task work by spawning child tasks under one parent job

Validation

  • mb-server: pnpm build
  • mb-server: focused Vitest slice across flow/task/doctor surfaces

@openclaw-barnacle openclaw-barnacle Bot added size: M maintainer Maintainer-authored PR labels Apr 1, 2026
@greptile-apps

greptile-apps Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds managed-flow child task spawning (runTaskInFlow) and makes flow cancellation "sticky" so external orchestrators can stop scheduling new work immediately while in-flight children finish asynchronously.

Key changes:

  • runTaskInFlow in task-executor.ts gates on cancelRequestedAt and terminal status before creating a task, inheriting ownerKey/requesterOrigin from the parent flow.
  • cancelFlowById is refactored into a two-phase approach: record cancel intent first (markFlowCancelRequested), then attempt child shutdown, then settle the flow only when no active children remain.
  • syncManagedFlowCancellationFromTask in task-registry.ts finalizes cancel-requested managed flows to cancelled whenever a task update causes all children to be settled — with a two-attempt retry loop to survive the revision bump made by the preceding syncFlowFromTask call.
  • isActiveTaskStatus and isTerminalFlowStatus are duplicated in both task-executor.ts and task-registry.ts (style note — see inline comment).

Confidence Score: 5/5

Safe to merge — logic is correct, all new behaviour is covered by targeted tests, and the only finding is a minor code-duplication style note.

No P0/P1 issues found. The FlowRecord/FlowUpdateFailure discriminant is safe (FlowRecord has no reason field). The two-phase cancel correctly prevents new task spawns after cancel intent is recorded. The retry loop in syncManagedFlowCancellationFromTask is sufficient for Node.js's single-threaded event loop. The only finding is duplicated isActiveTaskStatus/isTerminalFlowStatus helpers across two modules (P2).

No files require special attention.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/tasks/task-executor.ts
Line: 387-396

Comment:
**Duplicated helpers already defined in `task-registry.ts`**

`isActiveTaskStatus` (line 387) and `isTerminalFlowStatus` (line 391) are identical to the helpers added to `src/tasks/task-registry.ts` (lines 71–79). If the import boundaries allow it, these could be extracted into a small shared internal utility (e.g., `task-status-utils.ts`) so the definitions stay in one place. If the circular-import risk makes that awkward, a brief inline comment explaining the intentional duplication would help future readers.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Tasks/flows: add managed flow task execu..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 644628d2bf

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +549 to +553
if (isTerminalFlowStatus(flow.status)) {
return {
found: true,
cancelled: false,
reason: `Flow is already ${flow.status}.`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Cancel active child tasks before terminal-flow early return

This early return prevents cancelFlowById from even attempting cancelTaskById when the flow is already terminal. For managed flows, status is not mirrored from task state, so a flow can be marked failed/cancelled while child tasks are still queued/running; in that case this change leaves those child sessions running indefinitely instead of shutting them down. Previously the function canceled active children first and only then reported terminal flow status.

Useful? React with 👍 / 👎.

Comment on lines 387 to 396
@@ -386,6 +395,145 @@ function isTerminalFlowStatus(status: FlowRecord["status"]): boolean {
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Duplicated helpers already defined in task-registry.ts

isActiveTaskStatus (line 387) and isTerminalFlowStatus (line 391) are identical to the helpers added to src/tasks/task-registry.ts (lines 71–79). If the import boundaries allow it, these could be extracted into a small shared internal utility (e.g., task-status-utils.ts) so the definitions stay in one place. If the circular-import risk makes that awkward, a brief inline comment explaining the intentional duplication would help future readers.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tasks/task-executor.ts
Line: 387-396

Comment:
**Duplicated helpers already defined in `task-registry.ts`**

`isActiveTaskStatus` (line 387) and `isTerminalFlowStatus` (line 391) are identical to the helpers added to `src/tasks/task-registry.ts` (lines 71–79). If the import boundaries allow it, these could be extracted into a small shared internal utility (e.g., `task-status-utils.ts`) so the definitions stay in one place. If the circular-import risk makes that awkward, a brief inline comment explaining the intentional duplication would help future readers.

How can I resolve this? If you propose a fix, please make it concise.

@aisle-research-bot

aisle-research-bot Bot commented Apr 1, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

We found 5 potential security issue(s) in this PR:

# Severity Title
1 🟠 High Broken access control in flows CLI: ownerKey lookup enables cross-owner flow disclosure and cancellation
2 🟠 High Symlink-following chmod/file clobbering via OPENCLAW_STATE_DIR in SQLite flow registry store
3 🟡 Medium Orphaned flow record on exception in ensureSingleTaskFlow() (potential storage/memory DoS)
4 🟡 Medium CLI flows commands leak potentially sensitive delivery/session metadata in JSON output
5 🟡 Medium Persistent DoS via NULL/invalid owner_key in flow registry SQLite migration/restore
1. 🟠 Broken access control in `flows` CLI: ownerKey lookup enables cross-owner flow disclosure and cancellation
Property Value
Severity High
CWE CWE-285
Location src/commands/flows.ts:159-234

Description

The openclaw flows CLI commands do not enforce owner scoping when resolving flows.

  • flows show and flows cancel call resolveFlowForLookupToken(opts.lookup), which accepts either a flowId or an ownerKey and returns the latest flow for that owner.
  • flows cancel then calls cancelFlowById({ flowId }) (non-owner-scoped), allowing cancellation of flows belonging to other owners.
  • flows list enumerates all flow records and can output full flow metadata plus linked tasks in JSON.

If the CLI is usable by untrusted users in a shared/multi-tenant environment (e.g., multiple agents/owners on the same deployment, remote execution wrappers, exposed admin endpoints), a caller can:

  • Read another owner’s flow metadata (including ownerKey, goal, stateJson/waitJson via JSON output, and linked tasks)
  • Cancel another owner’s running flow by providing their flowId or ownerKey

Vulnerable code:

const flow = resolveFlowForLookupToken(opts.lookup);
...
const result = await cancelFlowById({ cfg: loadConfig(), flowId: flow.flowId });

Recommendation

Enforce owner scoping (or explicit admin authorization) for all flow inspection and mutation operations.

Options:

  1. If CLI actions should be owner-scoped: require/derive a callerOwnerKey (from config/session identity) and use the owner-scoped helpers:
import { resolveFlowForLookupTokenForOwner } from "../tasks/flow-owner-access.js";
import { cancelFlowByIdForOwner } from "../tasks/task-executor.js";

const flow = resolveFlowForLookupTokenForOwner({
  token: opts.lookup,
  callerOwnerKey,
});
if (!flow) { /* not found */ }

await cancelFlowByIdForOwner({ cfg: loadConfig(), flowId: flow.flowId, callerOwnerKey });
  1. If this is intended as an operator/admin-only tool: remove ownerKey-based lookup (accept only flowId), and/or add an explicit --all-owners/--admin gate to list/show/cancel that is disabled by default.

Also consider filtering flows list output to the caller’s owner by default (and requiring explicit elevation for global listings).

2. 🟠 Symlink-following chmod/file clobbering via OPENCLAW_STATE_DIR in SQLite flow registry store
Property Value
Severity High
CWE CWE-59
Location src/tasks/flow-registry.store.sqlite.ts:315-325

Description

The SQLite-backed flow registry store derives its database path from OPENCLAW_STATE_DIR (via resolveFlowRegistrySqlitePath(process.env)), then performs filesystem operations that follow symlinks and are subject to TOCTOU races:

  • mkdirSync(dir, { recursive: true }) and chmodSync(dir, 0o700) are executed on dir without verifying it is a real directory and not a symlink.
  • For the database file and its WAL sidecars (registry.sqlite, registry.sqlite-wal, registry.sqlite-shm), the code checks existsSync() and then runs chmodSync() on the path. chmod follows symlinks on most platforms, so a pre-planted symlink can cause permission changes on an attacker-chosen target.
  • The store then opens SQLite at pathname (new DatabaseSync(pathname)), which may create/clobber the target file if the path is redirected.

If an attacker can influence OPENCLAW_STATE_DIR for a more-privileged process, or can create/replace files under the resolved state directory (including symlinks), they can potentially:

  • Change permissions on arbitrary files/directories accessible to the process (via chmodSync).
  • Cause the process to create/modify an attacker-chosen SQLite file path (via DatabaseSync(pathname)), potentially clobbering sensitive files.

Vulnerable code:

mkdirSync(dir, { recursive: true, mode: FLOW_REGISTRY_DIR_MODE });
chmodSync(dir, FLOW_REGISTRY_DIR_MODE);
...
if (existsSync(candidate)) {
  chmodSync(candidate, FLOW_REGISTRY_FILE_MODE);
}

Recommendation

Harden filesystem handling for the state directory and SQLite files:

  1. Do not follow symlinks when setting permissions. Use lstatSync() to detect symlinks and refuse them, or open file descriptors with O_NOFOLLOW (where available) and operate on the fd.
  2. Avoid TOCTOU (existsSyncchmodSync). Prefer opening the file securely first, then fchmodSync(fd, mode).
  3. Validate/lock down OPENCLAW_STATE_DIR for privileged contexts (e.g., require it to be under the invoking user's home directory, or ignore env overrides when running with elevated privileges).

Example approach (POSIX-oriented):

import { mkdirSync, lstatSync, openSync, fchmodSync, closeSync } from "node:fs";
import { constants } from "node:fs";

function safeChmodFileNoSymlink(p: string, mode: number) {
  const st = lstatSync(p);
  if (st.isSymbolicLink()) throw new Error(`Refusing to chmod symlink: ${p}`);
  const fd = openSync(p, constants.O_RDWR | constants.O_NOFOLLOW);
  try { fchmodSync(fd, mode); } finally { closeSync(fd); }
}

Also ensure the flow registry directory is created with correct ownership and permissions and is not a symlink before use.

3. 🟡 Orphaned flow record on exception in ensureSingleTaskFlow() (potential storage/memory DoS)
Property Value
Severity Medium
CWE CWE-772
Location src/tasks/task-executor.ts:50-82

Description

ensureSingleTaskFlow() creates a new flow record and then attempts to link the task to it. If an exception is thrown after the flow is created (e.g., linkTaskToFlowById() throwing ParentFlowLinkError or any unexpected persistence/runtime error), the catch handler logs and returns the original task without deleting the newly created flow record, leaving an orphaned flow.

Impact:

  • Orphaned flows can accumulate in the flow registry, bloating persisted state and making flows list/show leak stale metadata.
  • Repeated triggering (e.g., by repeatedly creating eligible tasks under conditions that cause linkTaskToFlowById() to throw) can cause unbounded growth → potential denial of service via disk/memory usage.

Vulnerable code:

const flow = createFlowForTask({ task: params.task, requesterOrigin: params.requesterOrigin });
const linked = linkTaskToFlowById({ taskId: params.task.taskId, flowId: flow.flowId });
...
} catch (error) {
  log.warn("Failed to create one-task flow for detached run", { ... });
  return params.task; // flow not deleted here
}

Recommendation

Track the created flow ID and ensure it is deleted on any failure after creation.

One approach is to use a let flowId: string | undefined and a catch/finally cleanup:

let flowId: string | undefined;
try {
  const flow = createFlowForTask({ task: params.task, requesterOrigin: params.requesterOrigin });
  flowId = flow.flowId;
  const linked = linkTaskToFlowById({ taskId: params.task.taskId, flowId });
  if (!linked || linked.parentFlowId !== flowId) {
    deleteFlowRecordById(flowId);
    return linked ?? params.task;
  }
  return linked;
} catch (e) {
  if (flowId) {
    deleteFlowRecordById(flowId);
  }
  throw e; // or return params.task, but after cleanup
}

If the intention is to swallow errors and continue, still perform the cleanup before returning.

4. 🟡 CLI flows commands leak potentially sensitive delivery/session metadata in JSON output
Property Value
Severity Medium
CWE CWE-200
Location src/commands/flows.ts:125-140

Description

The new openclaw flows CLI commands output full FlowRecord objects and linked TaskRecord objects when --json is used.

Because these records include fields like:

  • FlowRecord.ownerKey (session key / owner identifier)
  • FlowRecord.requesterOrigin (DeliveryContext containing channel, to, accountId, threadId)
  • task-level identifiers such as TaskRecord.requesterSessionKey, TaskRecord.ownerKey, TaskRecord.childSessionKey, TaskRecord.runId, and potentially error strings

…the JSON output can disclose PII (chat/account identifiers), internal routing/session keys, and operational metadata into terminals, CI logs, or shared artifacts if users run these commands in automated environments.

Vulnerable code (JSON output includes raw records):

flows: flows.map((flow) => ({
  ...flow,
  tasks: listTasksForFlowId(flow.flowId),
  taskSummary: getFlowTaskSummary(flow.flowId),
})),

and:

JSON.stringify({
  ...flow,
  tasks,
  taskSummary,
})

While this is a local CLI, the disclosure is still impactful because JSON output is commonly redirected/archived, and these fields are not obviously safe for broad exposure.

Recommendation

Redact or minimize sensitive fields by default, and require an explicit opt-in for verbose/raw dumping.

Suggested approach:

  • For --json, return a sanitized DTO that excludes/obfuscates identifiers like ownerKey, requesterOrigin.to, requesterOrigin.accountId, requesterSessionKey, childSessionKey, etc.
  • Add a separate flag such as --json-verbose (or --unsafe-json) for full internal records.

Example:

function redactDeliveryContext(ctx?: DeliveryContext) {
  if (!ctx) return undefined;
  return {
    channel: ctx.channel,// Avoid emitting direct message targets/account ids by default
    to: ctx.to ? "[redacted]" : undefined,
    accountId: ctx.accountId ? "[redacted]" : undefined,
    threadId: ctx.threadId != null ? "[redacted]" : undefined,
  };
}

function toSafeFlow(flow: FlowRecord) {
  return {
    flowId: flow.flowId,
    syncMode: flow.syncMode,
    status: flow.status,
    revision: flow.revision,
    goal: flow.goal,
    controllerId: flow.controllerId,
    requesterOrigin: redactDeliveryContext(flow.requesterOrigin),// omit ownerKey/stateJson/waitJson unless verbose
  };
}// in --json path:
flows: flows.map((flow) => ({
  ...toSafeFlow(flow),
  taskSummary: getFlowTaskSummary(flow.flowId),
})),

Document the security/privacy implications in CLI help text for the verbose option.

5. 🟡 Persistent DoS via NULL/invalid owner_key in flow registry SQLite migration/restore
Property Value
Severity Medium
CWE CWE-754
Location src/tasks/flow-registry.store.sqlite.ts:248-255

Description

The flow registry restore path can be crashed (and repeatedly re-crashed on subsequent CLI runs) by a corrupted or partially-migrated SQLite registry where flow_runs.owner_key is NULL or blank.

  • ensureSchema() conditionally adds owner_key via ALTER TABLE without a NOT NULL constraint and only backfills from owner_session_key when present.
  • If any existing row lacks owner_session_key (or the DB is attacker-modified), owner_key can remain NULL.
  • loadFlowRegistryStateFromSqlite() converts rows into FlowRecord objects without validating owner_key.
  • During restore, normalizeRestoredFlowRecord() calls assertFlowOwnerKey(record.ownerKey) which throws when the value is missing/empty, aborting ensureFlowRegistryReady() and causing commands that touch flows to fail.

Vulnerable code (migration/backfill leaves nullable owner_key):

if (!hasFlowRunsColumn(db, "owner_key") && hasFlowRunsColumn(db, "owner_session_key")) {
  db.exec(`ALTER TABLE flow_runs ADD COLUMN owner_key TEXT;`);
  db.exec(`
    UPDATE flow_runs
    SET owner_key = owner_session_key
    WHERE owner_key IS NULL
  `);
}

And restore-time hard failure:

ownerKey: assertFlowOwnerKey(record.ownerKey),

Recommendation

Harden both the migration and restore paths so a corrupted registry cannot brick the CLI.

  1. Migration/backfill: ensure all rows end up with a non-null owner_key.

    • If you can safely derive it, backfill it for all rows.
    • Otherwise, delete/quarantine invalid rows.
  2. Enforce invariants: SQLite cannot add a NOT NULL constraint via ALTER TABLE ... ADD COLUMN in-place for existing tables; consider rebuilding the table or adding a validation step.

  3. Restore robustness: do not let a single bad row crash restore. Skip invalid rows (and optionally log/repair).

Example approach (repair on load):

// after ALTER TABLE
db.exec(`UPDATE flow_runs SET owner_key = '' WHERE owner_key IS NULL;`);// OR delete invalid rows
db.exec(`DELETE FROM flow_runs WHERE owner_key IS NULL OR trim(owner_key) = ''`);

Example approach (defensive restore):

for (const [flowId, flow] of restored.flows) {
  try {
    flows.set(flowId, normalizeRestoredFlowRecord(flow));
  } catch {// skip or repair
  }
}

Analyzed PR: #58939 at commit f26951c

Last updated on: 2026-04-02T10:04:24Z

Latest run failed. Keeping previous successful results. Trace ID: 019d4d9624bac26c634e517fd4bf0b75.

Last updated on: 2026-04-02T10:44:44Z

Latest run failed. Keeping previous successful results. Trace ID: 019d4d9fea7671e0633b221c1090d5dd.

Last updated on: 2026-04-02T11:11:31Z

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0e82d237a8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +599 to +603
if (isTerminalFlowStatus(flow.status)) {
return {
found: true,
cancelled: false,
reason: `Flow is already ${flow.status}.`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Cancel active child tasks before terminal-flow short-circuit

Fresh evidence in this commit: cancelFlowById now returns immediately when the flow status is terminal, before the active-child cancellation loop runs. In managed flows, flow status can become failed/cancelled independently of child task state, so this early return can leave queued/running children alive and their sessions never canceled, which breaks the intended sticky-cancel shutdown behavior.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 27e6baa3dc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +652 to +654
if ("reason" in cancelRequestedFlow) {
return {
found: true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retry cancel-intent conflicts before aborting cancellation

If requestFlowCancel hits a revision conflict (for example, the controller updates flow state between the initial getFlowById and this call), this branch returns immediately and never reaches the child-cancellation loop below. In that case cancelFlowById reports failure without even attempting cancelTaskById, so active child sessions keep running until someone retries manually. This regression is introduced by making cancel-intent CAS a hard precondition instead of retrying with result.current/fresh flow data.

Useful? React with 👍 / 👎.

@mbelinky mbelinky force-pushed the workspace/clawflow-repack-v1 branch from c0ede2a to 7c6f535 Compare April 2, 2026 09:32
@mbelinky mbelinky force-pushed the workspace/clawflow-run-task-in-flow branch from 27e6baa to f26951c Compare April 2, 2026 09:32
@openclaw-barnacle openclaw-barnacle Bot added the commands Command implementations label Apr 2, 2026
@mbelinky mbelinky changed the title Tasks/flows: add managed flow task execution TaskFlow: add managed child task execution Apr 2, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f26951c10a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread CHANGELOG.md Outdated
- Channels/session routing: move provider-specific session conversation grammar into plugin-owned session-key surfaces, preserving Telegram topic routing and Feishu scoped inheritance across bootstrap, model override, restart, and tool-policy paths.
- WhatsApp/reactions: add `reactionLevel` guidance for agent reactions. Thanks @mcaxtr.
- Feishu/comments: add a dedicated Drive comment-event flow with comment-thread context resolution, in-thread replies, and `feishu_drive` comment actions for document collaboration workflows. (#58497) thanks @wittam-01.
<<<<<<< HEAD

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove unresolved merge marker from changelog

The committed <<<<<<< HEAD line is an unresolved merge-conflict marker in the Unreleased section, so release notes now contain conflict syntax instead of valid content. This can break changelog tooling/parsing and should be removed before landing.

Useful? React with 👍 / 👎.

@mbelinky mbelinky force-pushed the workspace/clawflow-repack-v1 branch from 7c6f535 to 9c946d5 Compare April 2, 2026 09:46
@mbelinky mbelinky force-pushed the workspace/clawflow-run-task-in-flow branch from f26951c to 411d718 Compare April 2, 2026 09:46
@mbelinky mbelinky force-pushed the workspace/clawflow-run-task-in-flow branch from 411d718 to 08ed516 Compare April 2, 2026 09:49
@mbelinky mbelinky force-pushed the workspace/clawflow-run-task-in-flow branch from 08ed516 to af82b86 Compare April 2, 2026 09:52
@mbelinky mbelinky force-pushed the workspace/clawflow-run-task-in-flow branch from af82b86 to c473c0c Compare April 2, 2026 09:56

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c473c0cf8d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +147 to +151
if (flow.cancelRequestedAt != null) {
throw new ParentFlowLinkError(
"cancel_requested",
"Parent flow cancellation has already been requested.",
{ flowId, status: flow.status },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve idempotent child-task replays after cancel intent

This new cancel_requested rejection runs inside assertParentFlowLinkAllowed, which createTaskRecord calls before it attempts run-id deduplication (findExistingTaskForCreate). That means a replay of an already-created child run (same runId/scope) will now throw once cancelRequestedAt is set, instead of returning the existing task record. In at-least-once orchestrators, this breaks idempotent recovery and can make callers treat an existing child as missing right after cancellation intent is recorded.

Useful? React with 👍 / 👎.

@mbelinky mbelinky force-pushed the workspace/clawflow-repack-v1 branch from 1e51229 to c990938 Compare April 2, 2026 10:17
@mbelinky mbelinky deleted the branch workspace/clawflow-repack-v1 April 2, 2026 10:17
@mbelinky mbelinky closed this Apr 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands Command implementations maintainer Maintainer-authored PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant