Skip to content

isSystem: true has at least three distinct, undocumented side effects across three packages — each one has cost an app-side bug #4707

Description

@os-zhuang

Filed from the HotCRM reference app after the third one bit us in a single day. Each was found separately, by a different task, and none is written down anywhere that connects it to the others.

The three behaviours

isSystem: true on a write is used by the seed loader and by internal writers. Across three different packages it changes three unrelated things:

#packageeffecthow we found it
1ObjectQL (applySystemFields)owner_id is not injected — the row is written with no platform ownerhotcrm#622: demo_bootstrap had to sweep and stamp ownership after the fact
2write pipelinereadonly stripping is bypassed — a readonly field CAN be writtenhotcrm#613: relied on deliberately, so a seed_key column exists that only the seed loader can write
3plugin-sharinggrant materialisation is skipped — the record-write hook returns early, so no sys_record_share rows are createdhotcrm#640: every seeded row is isSystem, so a fully-configured sharing rule granted nothing until a rule was re-evaluated

Number 3 is the one that motivated this issue. On a fresh install we had: 9 sharing rules installed, 9 accounts matching their criteria, users holding the right positions — and sys_record_shareempty. Every visible layer said the feature was configured. Nothing anywhere said that the seed path had skipped materialisation, and no amount of reading the sharing metadata could have revealed it.

Why this is worth a single issue rather than three

Individually each is defensible. Together they mean isSystem is not one concept — it is at least three policies (ownership, field protection, sharing) sharing one boolean, implemented in three packages, discoverable only by reading each package's source.

That has two concrete consequences:

What we would like

  1. Document the full set. The minimum useful artifact is one table listing every behaviour keyed off isSystem, in one place, maintained as the authority. If there is a fourth we have not hit yet, that table is how we would find out.
  2. Consider splitting the concept. Ownership injection, readonly bypass, and sharing materialisation are independent decisions; a seed loader plausibly wants Add metamodel interfaces for ObjectQL/ObjectUI contract #1 and ✨ Set up Copilot instructions #2 but usually notImplement ObjectStack protocol specification with Zod schemas and TypeScript interfaces #3. If they stay one flag, say so and say why.
  3. Make Implement ObjectStack protocol specification with Zod schemas and TypeScript interfaces #3 observable. A seed run that writes N rows to an object covered by an active sharing rule and materialises 0 grants is worth one INFO line ("sharing materialisation skipped for isSystem writes; re-evaluate rules or restart to backfill"). Today the only way to learn this is to query sys_record_share, find it empty, and go read plugin-sharing's source.

Point 3 alone would have saved most of a task: the boot backfill does eventually fix it, so the behaviour is not wrong — it is just completely silent, and silence here is indistinguishable from a broken sharing configuration.

Related: hotcrm#622, hotcrm#613, hotcrm#640 (PR hotcrm#652), #4698.

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