Skip to content

runtime, metadata-protocol: the seed-write execution context is a private constant in two places, so every seeder outside those two files re-spells it #17178

Description

@claude

Filed from objectstack#15951 (hotcrm#1579 step 5a) under that card's binding design rule: "if a method needs a semantic the kernel does not expose, that is a kernel gap: file it, do not re-implement it in verify." This is one of the two gaps that card hit. It is a kernel gap, not a verify defect — nothing here blocks #15951, which spells the constant once, in one place, with a comment pointing back at the owner.

Measured (objectstack origin/main 5d12b16e, 2026-09-09)

The write context a seed insert must use is three flags — isSystem, skipTriggers, seedReplay — and the platform holds two private copies of it:

  • packages/metadata-protocol/src/seed-loader.ts:2089private static readonly SEED_OPTIONS = { context: { isSystem: true, skipTriggers: true, seedReplay: true } } as const;
  • packages/runtime/src/app-plugin.ts:34const SEED_WRITE_OPTIONS = { context: { isSystem: true, skipTriggers: true, seedReplay: true } } as const; — module-private, and its own docblock says it "mirrors SeedLoaderService.SEED_OPTIONS", i.e. the duplication is already known and written down at the second site.

That docblock also records why the value is load-bearing rather than cosmetic: skipTriggers is what suppresses "on create" automation for seed rows, isSystem alone does not suppress dispatch, and the two basic-insert fallbacks in app-plugin.ts once seeded with automation live while the main path had it suppressed (#3760, a self-trigger loop that wedged first boot).

Why it is a gap and not a style point

A constant whose divergence re-opens a boot-wedging defect has no exported spelling, so every writer that needs the seed posture must copy it. #15951 needed exactly that: @objectstack/verify's new seed(object, rows) writes fixture rows the way the platform replays a stack's declared data[], so it now carries a third copy (packages/verify/src/handle.ts, SEED_CONTEXT, spelled with a comment naming app-plugin.ts as the owner). Three copies of a three-flag invariant, none of which any gate holds equal to the others.

The copies are also not equal today in one respect worth noting: SEED_OPTIONS and SEED_WRITE_OPTIONS are { context: { ... } } wrappers, i.e. whole option bags, while a caller that already has an options bag needs only the inner ExecutionContext.

The ask

Export the seed-write execution context once, from wherever the platform decides owns it, and have both existing sites read it. Shape is the maintainer's call; the two candidates the code suggests are the inner ExecutionContext (composes into any options bag) or the whole options bag (matches both current call sites verbatim). A pin holding the sites equal would be worth more than either.

Not in this card: any change to what the three flags mean, or to seed behaviour.

Refs: objectstack#15951 (the card that hit it) - hotcrm#1579 (epic) - #3760 (the self-trigger loop skipTriggers prevents).


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

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions