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:2089 — private static readonly SEED_OPTIONS = { context: { isSystem: true, skipTriggers: true, seedReplay: true } } as const;
packages/runtime/src/app-plugin.ts:34 — const 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
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 averifydefect — nothing here blocks #15951, which spells the constant once, in one place, with a comment pointing back at the owner.Measured (objectstack
origin/main5d12b16e, 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:2089—private static readonly SEED_OPTIONS = { context: { isSystem: true, skipTriggers: true, seedReplay: true } } as const;packages/runtime/src/app-plugin.ts:34—const SEED_WRITE_OPTIONS = { context: { isSystem: true, skipTriggers: true, seedReplay: true } } as const;— module-private, and its own docblock says it "mirrorsSeedLoaderService.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:
skipTriggersis what suppresses "on create" automation for seed rows,isSystemalone does not suppress dispatch, and the two basic-insert fallbacks inapp-plugin.tsonce 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 newseed(object, rows)writes fixture rows the way the platform replays a stack's declareddata[], so it now carries a third copy (packages/verify/src/handle.ts,SEED_CONTEXT, spelled with a comment namingapp-plugin.tsas 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_OPTIONSandSEED_WRITE_OPTIONSare{ context: { ... } }wrappers, i.e. whole option bags, while a caller that already has an options bag needs only the innerExecutionContext.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
skipTriggersprevents).Generated by Claude Code