QA-source: #20674 · automation.packaged-flow-subflow-disable-refusal · c5
Recorded while grounding as docs/qa/platform-checklist/FOLLOW-UPS.md §8a D19 (2026-08-26); no card existed. Now measured live.
What happens
Disabling a packaged flow that another packaged flow calls as a subflow is refused with 409 DELETE_RESTRICTED and the remedy "Disable the calling flow first, or leave this one armed." Following that remedy does not help: after the caller is disabled, the child's disable is refused again with the same message, naming the already-disabled caller.
Measured on main at 6bff748b (showcase), twice on the subflow pair and once on the map pair on a fresh boot.
Reproduction
- As the seeded admin:
POST /api/v1/automation/showcase_notify_owner/toggle {"enabled":false} → 409 DELETE_RESTRICTED "Flow 'showcase_notify_owner' cannot be disabled while 1 packaged flow still calls it as a subflow: 'showcase_task_done_notify_owner'. … Disable the calling flow first, or leave this one armed."
POST /api/v1/automation/showcase_task_done_notify_owner/toggle {"enabled":false} → 200; its sys_metadata_activation row reads active: false and /_status shows enabled: false.
- Retry step 1. Expected: 200 and a ledger row
active: false for showcase_notify_owner. Actual: 409 DELETE_RESTRICTED, same sentence, still naming showcase_task_done_notify_owner.
- Map pair, same result: disable
showcase_release_signoff (200), then showcase_one_task_signoff is still refused naming it.
Mechanism (read from source at 6bff748b)
packagedSubflowCallers in packages/services/service-automation/src/engine.ts scans the registered flow map, skipping self and non-packaged callers only — it never asks whether a caller is ledger-disabled (flowLedgerDisabled) or status-disabled. toggleFlow throws from that list before any durable write. ADR-0126 §7.3 calls the refusal "honest, actionable (disable the callers first, or don't)"; the first branch is unreachable.
Expected
Either a disabled caller no longer guards its callee (so the prescribed sequence completes), or the refusal stops prescribing a sequence the door will refuse. The engine-level pins in flow-activation-ledger.test.ts do not cover the sequence.
Full evidence chain: #20674 (F-3).
Generated by Claude Code
QA-source: #20674 · automation.packaged-flow-subflow-disable-refusal · c5
Recorded while grounding as docs/qa/platform-checklist/FOLLOW-UPS.md §8a D19 (2026-08-26); no card existed. Now measured live.
What happens
Disabling a packaged flow that another packaged flow calls as a subflow is refused with 409
DELETE_RESTRICTEDand the remedy "Disable the calling flow first, or leave this one armed." Following that remedy does not help: after the caller is disabled, the child's disable is refused again with the same message, naming the already-disabled caller.Measured on
mainat6bff748b(showcase), twice on the subflow pair and once on the map pair on a fresh boot.Reproduction
POST /api/v1/automation/showcase_notify_owner/toggle {"enabled":false}→ 409DELETE_RESTRICTED"Flow 'showcase_notify_owner' cannot be disabled while 1 packaged flow still calls it as a subflow: 'showcase_task_done_notify_owner'. … Disable the calling flow first, or leave this one armed."POST /api/v1/automation/showcase_task_done_notify_owner/toggle {"enabled":false}→ 200; itssys_metadata_activationrow readsactive: falseand/_statusshowsenabled: false.active: falseforshowcase_notify_owner. Actual: 409DELETE_RESTRICTED, same sentence, still namingshowcase_task_done_notify_owner.showcase_release_signoff(200), thenshowcase_one_task_signoffis still refused naming it.Mechanism (read from source at
6bff748b)packagedSubflowCallersinpackages/services/service-automation/src/engine.tsscans the registered flow map, skipping self and non-packaged callers only — it never asks whether a caller is ledger-disabled (flowLedgerDisabled) or status-disabled.toggleFlowthrows from that list before any durable write. ADR-0126 §7.3 calls the refusal "honest, actionable (disable the callers first, or don't)"; the first branch is unreachable.Expected
Either a disabled caller no longer guards its callee (so the prescribed sequence completes), or the refusal stops prescribing a sequence the door will refuse. The engine-level pins in
flow-activation-ledger.test.tsdo not cover the sequence.Full evidence chain: #20674 (F-3).
Generated by Claude Code