Skip to content

[needs decision] #16659's ruled fix refuses the repo's own four example scheduled flows at bind, and today a package-shipped flow has no legal organization to name #17150

Description

@os-trump

Filed by the domain:services PM seat (#6021) as the delivering seat's open_questions on #16659 / PR #17126, which asked PM to file rather than guess. ⛔ Correct call — every option below is a product decision.

⚠️ This gates #17126's landing, not its correctness. The PR implements the maintainer's ruling faithfully; the ruling simply did not anticipate that the repo's own examples cannot satisfy it.

The consequence, and it is not hypothetical

#16659's ruling — 「多组织定时任务本来只能在组织内运行,应该带组织ID,不允许跨组织的定时任务」 — is implemented as: a time-triggered flow declares its acting organization on the start node, and a flow declaring none is REFUSED at bind, no job registered. That refusal is consequence (3) of the ruling and is explicitly not a silent default and not a fallback to a platform organization.

⇒ These four flows in this repo are now refused, each named in the error (verified on the tree at ce7bae8b4):

flow file
task_reminder examples/app-todo/src/flows/task.flow.ts:10
overdue_escalation examples/app-todo/src/flows/task.flow.ts:62
showcase_scheduled_digest examples/app-showcase/src/automation/flows/index.ts:366
showcase_task_due_reminder examples/app-showcase/src/automation/flows/index.ts:1664

And they cannot be fixed in scope, because an organization id is minted at runtime and no example seeds a sys_organization row — so there is no value an author of a package-shipped flow could write. PR #17126 touches examples/ in zero files, deliberately.

The delivering seat refused to write a placeholder id, and that judgement is right: a value matching no row is exactly the "wrong organization_id, silently authoritative" outcome the ruling forbids, and strictly worse than the refusal.

⚠️ A correction to the supporting measurement, made by this seat

The delivery's report states: "no platform-organization constant exists anywhere in packages/ (zero non-test hits)." That is false. packages/runtime/src/http-dispatcher.ts:

/** Well-known system project id — bypassed for any authenticated user. */
private static readonly SYSTEM_ENVIRONMENT_ID = '00000000-0000-0000-0000-000000000001';
/** Well-known platform org id — members bypass project membership. */
private static readonly PLATFORM_ORG_ID       = '00000000-0000-0000-0000-000000000000';

and it is used at :1412 (if (activeOrganizationId === HttpDispatcher.PLATFORM_ORG_ID) return null;). One grep with three spellings found it. ⇒ a zero from a sweep that cannot answer "yes" is NOT MEASURED — this lane's own standing rule, applied here to a delivery's negative result.

⚠️ The conclusion may still stand — that constant is private, unexported, not authorable, and a well-known sentinel in the dispatcher's membership logic is not the same thing as a seeded sys_organization row a scheduled run could execute as. ⭐ But the option analysis changes: option A is not starting from nothing. There is already a documented well-known platform organization id, a sibling SYSTEM_ENVIRONMENT_ID in the same family, and the seed layer's os.org.id CEL binding (packages/spec/src/data/seed-loader.zod.ts:310) that the delivery itself cited as A's mechanism.

The decision

what it means cost
A (delivery's rec.) a symbolic organization reference a package-shipped flow can name, resolved per organization the way seeds already resolve os.org.id keeps the ruling intact and keeps the platform able to ship a scheduled flow in a package; ⚠️ needs the symbol designed — and now also needs to be reconciled with the existing PLATFORM_ORG_ID sentinel rather than inventing a second one
B rule that a scheduled flow is deployment data, never package source — the examples drop theirs or move them to seeded metadata, and the refusal is simply correct defensible, but it silently retires a capability the examples currently demonstrate; that is a maintainer call, not a delivery one
C give the examples a seeded sys_organization row with a fixed id and have them name it works, but changes example seed data and makes every demo multi-organization-shaped

You are being asked for one letter — A, B or C.

A second, smaller reading the delivery asked for, and this seat's answer

Consequence (3) says "refused at validation/boot". I read that as per-flow refusal at BIND (boot), not at FlowSchema.parse. Is that the intended reading?

Yes, and no maintainer time is needed on it. Under bind-time refusal there is no path by which an organization-less time-triggered run reaches the data layer, which is the substance of (3). Parse-time would add no safety and would make every package-shipped scheduled flow unparseable — a strictly worse version of the same problem this card is about. ⛔ Raised here only because the delivery asked; ⚠️ ⛔ do not treat it as part of the A/B/C decision.

⚠️ A coverage hole this exposed, recorded rather than folded in

PR #17126's CI is green while those four example flows are refused at bind. ⇒ nothing in CI boots the examples' schedule bindings. That is a gap worth its own card once the decision above lands — a refusal that the repo's own examples trip and no gate notices is the same silence class this lane has spent the day on. ⛔ Not filed yet, because what the gate should assert depends on which letter you pick.

Related

#16659 (the card, ruled) · PR #17126 (the implementation, complete, parked on contract review and on this decision) · #17123 (the green-run-masks-zero-delivery hole, filed separately per the ruling's consequence 4) · #15207 / ADR-0131 D7 (where 方向三 lives, ruled out for #16659)

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions