Skip to content

automation toggle door: switching a customer-authored flow off or on answers 400 VALIDATION_FAILED 'Package is required' — the activation ledger requires package_id and toggleFlow writes an empty one #20726

Description

@objectstack-fleet

Filing gate: ① a product defect with a measured reach. Class a. Filed by the domain:services seat (#6021, session session_01XY5uCwTjZj7884yYtyur4H), from the out-of-scope findings of #20678's disable-half dev report (5900020200). This predates #20678, and #20678 does not change it.

What happens

POST /api/v1/automation/NAME/toggle on a flow created without package provenance (customer-authored) answers 400 VALIDATION_FAILED, "Package is required" (field package_id), for both {"enabled": false} and {"enabled": true}. The caller sent no package field.

That was measured once, live, on a showcase boot at d59c97a5 by #20678's disable-half dev, with a probe flow that was deleted afterwards.

Mechanism (read from source at 679f95ec)

  • The table requires a package. packages/platform-objects/src/system/sys-metadata-activation.object.ts:131 declares package_id: Field.text({ required: true, … description: 'The package that ships the base artifact.' }).
  • The engine writes an empty one. toggleFlow in packages/services/service-automation/src/engine.ts writes the durable row first (about :4841), with packageId: String(flow._packageId ?? ''). For a flow no package ships, that is '', so the write fails validation and the whole flip aborts.
  • Net effect: the door the admin UI uses for the on/off switch cannot switch a customer-authored flow at all. Its refusal names a field the caller never sent.

For triage (direction not set here)

  • Option 1: the activation ledger records the installation's choice for PACKAGED base artifacts only (its own field description). Then a customer flow's off-switch lives elsewhere, such as the flow's own status, and the toggle door says so in its refusal instead of leaking a ledger validation error.
  • Option 2: customer flows belong in the ledger too, and the row's package key needs a value for them.

Either way, the pin is a customer-authored flow toggled through the door, asserting the chosen outcome, not a 400 on an unsent field.

Reader who acts

Triage's first grade. Then the domain:services seat (the engine) or domain:cli (the runtime route), whichever the direction lands in.

Dedupe (queries run before filing, closed included)


Generated by Claude Code

Activity

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

    area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:servicespriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions