Fixes app re-install on workspaces that have already received the v2.5
`NormalizeCompositeFieldDefaultsCommand` backfill: those workspaces now
have non-null `defaultValue` on every composite system field (createdBy,
updatedBy, position, searchVector, …). The next `installApplication` →
`synchronizeFromManifest(isSystemBuild: false)` rebuilds the diff and
hits `FIELD_MUTATION_NOT_ALLOWED` on each row because the manifest TO
state never declared system fields, so the dispatcher saw them as
FROM-only and emitted bad delete/update actions.
## Root cause
`computeApplicationManifestAllUniversalFlatEntityMaps` walks
`manifest.objects[].fields` and never scaffolds the eight standard
system fields the runtime actually attaches on object creation
(`buildDefaultFlatFieldMetadatasForCustomObject`). On top of that,
the scaffolder seeded each system field's `universalIdentifier` with
`v4()`, so even if we wanted to mirror them on the TO side from the
manifest converter, the random UIDs would never line up with the rows
already in the workspace.
## Fix (three pieces)
1. **Switch `buildDefaultFlatFieldMetadatasForCustomObject` from `v4` to
`v5`.** Same pattern as `NAVIGATION_COMMAND_UUID_NAMESPACE`: every
system field's universalIdentifier is derived deterministically from
`${objectMetadataUniversalIdentifier}/${name}` against a new
`SYSTEM_FIELD_UUID_NAMESPACE`. Exported as
`computeSystemFieldUniversalIdentifier` so the manifest converter
and the upgrade migration both compute identical UUIDs.
2. **Inject the eight system fields into manifest TO.** Inside
`computeApplicationManifestAllUniversalFlatEntityMaps`, after each
`flatObjectMetadata` is added, call
`buildDefaultFlatFieldMetadatasForCustomObject({ skipNameField: true })`
and merge its eight rows into `flatFieldMetadataMaps`. Apps that
explicitly declare a field with one of the system names (e.g. an
`id: TEXT` regression) are left untouched so the existing
`validateObjectMetadataSystemFieldsIntegrity` validator still
surfaces the mistake.
3. **2-5 workspace upgrade migration:**
`2-5-workspace-command-1798600000000-refactor-system-field-universal-identifiers.command.ts`
rewrites every existing `isSystem: true` field whose name is one of
the eight standard names to the new v5 identifier (direct
`UPDATE core."fieldMetadata"` on the `universalIdentifier` column —
no FK references it, all DB joins are on the per-workspace `id`
PK), then invalidates the `flatFieldMetadataMaps` and
`flatObjectMetadataMaps` cache entries. Direct analogue of
`1-21-workspace-command-1775500013000-refactor-navigation-commands`.
After (1)+(2)+(3) ship, the dispatcher computes an empty diff for
system fields on app re-installs: TO and FROM contain the same eight
rows with the same v5 universalIdentifiers and the same scaffolder
defaults. The validator path is never hit.
## CI
`sync-application-system-fields-auto-attached.integration-spec.ts`
exercises three scenarios that would have caught this regression:
- First sync of an app whose object declares zero system fields ends
with the eight rows present and v5-addressed.
- Re-syncing the identical manifest is a no-op.
- A re-sync after a manually-cleared `defaultValue` on `createdBy`
(the exact post-2.5-backfill shape) succeeds — this is the case
that failed on prod after PR #20581 / the rolling 2.5 upgrade.
The existing dev-sync vitest suite never exercised
`installApplication` directly because the LOCAL sourceType short-
circuits the install handler, so the bug stayed silent until the CD
pipeline hit it on the registry-install path.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>