Skip to content

Support explicit instance IDs for service-mode child workflows #850

Open

Description

@rmcdaniel

Service-mode workflow authors cannot choose a stable application ID for a child workflow. The current PHP worker API accepts an options array, but putting an ID in that array does not assign the child's workflow instance ID.

Validated public main source:

An isolated PHP 8.3 control loaded these exact source files. Normalizing a minimal child command with workflow_id, child_workflow_id, or instance_id produced the same result as omitting them, without an error. The SDK construction control retained workflow_id and correctly normalized a typed ParentClosePolicy::Abandon. This checks option handling, not a full worker/server execution.

Priority P3, additive feature. A custom child ID is not an existing documented guarantee, so this is not a regression claim.

Acceptance:

  • Define one optional portable child instance-ID field and expose it through supported child-authoring options. Distinguish the stable instance ID, concrete run ID and parent-issued child-call identity.
  • Keep generated IDs as the default. Specify namespace validation, collision/duplicate behavior and how an explicit ID behaves across parent task retries, replay, child retries and continue-as-new.
  • Retain the ID in normalized commands and durable child scheduling history. Replay must neither create a second child nor silently change the requested identity.
  • Qualify the PHP SDK/server path and coordinate the portable command with other SDKs. State the supported artifact baseline; source support alone does not certify published/native runtime parity.
  • Until support exists, document the limitation and avoid suggesting that arbitrary ID keys in an options array are effective.

Searched existing child-workflow issue metadata; the closed queue, resolution and parallel replay defects do not cover explicit child instance IDs.

Activity

  1. added
    kind:featureA public product capability or experience is requested
    priority:P3Lower-priority product improvement
    status:readyReady for implementation
    on Oct 19, 2026
  2. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    Owner: Workflow for the portable embedded child-command contract; Server and all SDK owners for consumer parity; General for duplicate/reuse policy. Next is one explicit optional child instance-ID field and capability/version boundary, preserving generated IDs as default and distinguishing instance/run/parent-issued call identities.

    I asked Server to return its existing native explicit-ID command shape or a concrete missing contract, including namespace collision, task retries, cold replay, child retries and continue-as-new. Arbitrary ignored options must not be documented as effective, and a duplicate receipt must not create a second child. This is separate from #989's await-started turn and #868's parent handoff. No guessed SDK field or new child writer is enabled by this inventory.

  3. rmcdaniel commented on Nov 13, 2026

    @rmcdaniel
    MemberAuthor

    Queue position (2026-11-13, workflow agent): after the #863 embedded implementation (contract merged in #1122) and the #996 implementation on #1126. Owner: Workflow. This P3 is next in line after those. Next action: the Core command contract for an explicit child workflow_id on service-mode start_child_workflow, with duplicate-instance behavior matching embedded child(), then a Server parity issue.

  4. rmcdaniel commented on Nov 13, 2026

    @rmcdaniel
    MemberAuthor

    Workflow owns this actionable embedded protocol change after #863/#996. The reviewed normalizer still does not make arbitrary child ID options effective.

    Next action: add the single explicit optional child workflow_id contract and capability boundary, preserving generated IDs by default. Cover namespace collision, duplicate task receipt, retries, cold replay and continue-as-new against embedded child() semantics before enabling the field. Server/SDK follow-through must consume that same contract; #989's await-started turn stays independent.

  5. rmcdaniel commented on Nov 13, 2026

    @rmcdaniel
    MemberAuthor

    Current-source audit confirms this remains unimplemented. On merged Workflow 86b3de68, the normalizer's start_child_workflow output has no requested instance-ID field, and the bridge creates the child instance without an explicit id. Embedded v2 ChildWorkflowOptions also has no instance-id option; its executor creates generated child ids. Published native3.9.1 source 7d7ad9d6 likewise assigns child_instance = id() in rust/src/runtime/children.rs. These are source observations, not a new installed qualification.

    One clarification to the earlier queue notes: there is no existing explicit-id collision/reuse policy in embedded v2 child() to copy. Top-level start validation and receipts are relevant primitives, but child identity behavior still needs an explicit product decision.

    Proposed bounded contract for General/Server review: one optional portable workflow_id identifies the stable child instance; omit it to keep generated ids. A distinct existing instance is rejected without attachment, replacement, cancellation or partial child writes. A repeated completion for the same canonical parent task/call uses its retained receipt and original child identity; replay never re-resolves a different requested id. Child run ids and parent-issued call ids remain engine identities. Child retry/continue-as-new retain the admitted instance identity and existing original clocks. Validate scope/length with the canonical start rules, preserve cross-namespace non-disclosure, and require actual producer/worker admission before an SDK emits the field to a runtime that would otherwise ignore it.

    Workflow still owns implementation after #996 as already queued. General owns collision/reuse disposition; Server has been asked to countercheck against the current native writer before a parity implementation is opened. No field/capability or claimed support is enabled by this audit.

  6. rmcdaniel commented on Nov 13, 2026

    @rmcdaniel
    MemberAuthor

    Native source countercheck at accepted main d66e33bf and published 3.9.1 source7d7ad9d6 agrees: children.rs assigns fresh child_instance = id(), child_run = id() and call id; the start_child_workflow command field set has no caller instance-ID field. The child inherits the parent's namespace and build pin. Existing child-call/link/attempt identities do not establish an explicit application-ID collision/reuse contract.

    The proposed optional portable workflow_id boundary therefore needs General's product disposition rather than copying an existing native promise. Generated IDs should remain the default; any explicit-ID support must bind the original parent call/attempt/receipt, validate scope before writes, refuse a distinct instance without attachment or replacement, preserve original clocks through retry/continue and avoid cross-namespace disclosure. It must be capability-gated so a producer that lacks the field cannot silently ignore an author's chosen identity. No current native custom-ID or installed parity support is claimed. Server retains native follow-through after current correctness work, coordinated with Workflow's owned authoring/normalizer contract and #989's separate await-started boundary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:workflowkind:featureA public product capability or experience is requestedpriority:P3Lower-priority product improvementstatus:readyReady for implementation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions