entity

Parameter Group

The authoring grouping that organizes related ParameterKeys for humans. No lifecycle. The source a Revit UI group projection derives from — not itself a Revit artifact.

Entity(Aggregate Root)Status: Implemented in api-v1Aggregate Root

Purpose

A parameter group is the authoring grouping that organizes related ParameterKeys for humansDimensions, Materials and Finishes, Identity Data. It exists so a steward reading the dictionary in Airtable, or an author reading a property palette, sees related parameters together.

It carries no semantics. Value semantics live on ParameterSpec, presentation on ParameterControl, and applicability on ClassParameter. A group is a label and an ordering hint, nothing more.

Airtable table parameter_groups. A key points at a group through ParameterKey.parameterGroupId, which is optional at every lifecycle stage — a key never needs a group to be created, activated, approved, or archived.

No lifecycle

A parameter group has no lifecycle. It exists or it does not, and its only mutation is a rename.

Invariants

  • name is required and non-empty after trimming (PARAMETER_GROUP_NAME_REQUIRED), enforced on create, on rename, and on rehydrate. Rehydrating a row with a blank name throws rather than defaulting.
  • Group names are unique case-insensitively. CreateParameterGroupUseCase and UpdateParameterGroupUseCase both look the candidate name up before writing and return DuplicateParameterGroupNameError on a collision with any other group.
  • A rename to the same name is a no-op: rename returns success without recording an event, and the use case skips the Airtable write entirely when no event was recorded. That is deliberate — an AT-C1 “when record updated” automation would otherwise loop.

sortOrder and revitUiGroupTypeId exist as Airtable columns on parameter_groups and are read by the Revit derivation projectors, but they are not aggregate state: ParameterGroup holds only id and name, the Airtable mapper writes only those two fields, and the update contract accepts only name.

Relationship to Revit grouping

A parameter group is the source a Revit group projection derives from; it is not itself a Revit artifact. It has no ForgeTypeId of its own and Revit never sees a BuildPlan group id.

RevitUiGroupProjector turns a group into a ProjectedRevitUiGroup — a Revit property-palette group carrying a Forge groupTypeId. The group’s revitUiGroupTypeId is accepted only when it matches the Forge group pattern (autodesk.parameter.group:… or autodesk.revit.group:… with a semantic version suffix); anything else, including a missing group, falls back to autodesk.parameter.group:data-1.0.0 with usedFallback: true. The fallback is reported, not hidden: the derivation-drift report raises revit_ui_group_missing_or_invalid for every projection that used it, and missing_group for a key with no group at all.

Do not conflate this with ProjectedSharedParameterFileGroup. That is the shared-parameter-file *GROUP row, and package generation derives it from the root of the binding ObjectClass’s single-parent lineage (SharedParameterFileObjectClassGroupProjector, ADR-0046) — an entirely different input. The two groupings answer different questions: UI palette placement versus SPF file structure.

One caveat worth stating plainly, because the names invite the mistake: a second projector, SharedParameterFileGroupProjector, does shape a ParameterGroup into the same ProjectedSharedParameterFileGroup interface, and the derivation-metadata read path still uses it. That path is a legacy derivation read, not SPF package generation. Package *GROUP assignment is ObjectClass lineage; only the drift/derivation read projects parameter_groups into that shape.

Domain Events

Exactly one, from ParameterGroup.events.ts:

EventEmitted byPayload
ParameterGroupChangedcreate (change: 'created') and rename (change: 'renamed')parameterGroupId, change, name, previousName, changedAt

previousName is null on created and carries the prior label on renamed.

ParameterGroupChanged is consumed inside the module. CanonicalProjectionMetadataChangedHandler is registered for it and calls ResyncDerivedProjectionMetadataUseCase.resyncForParameterGroup, which walks every projection derived from the group and refreshes its non-overridden metadata. Renaming a group therefore resyncs Revit projection metadata. The handler is idempotent on the event’s own identity — group id plus changedAt, change, name, and previousName — never on projection state.

A resync that changes shared-parameter-file output on an approved projection demotes it to draft. See RevitParameterProjection.

OpenAPI Operations

assignParameterKeyToGroup is a PUT on the key, not the group — the reference lives on ParameterKey and a null body clears it.

The Airtable steward path is documented in MUTATION_ROUTING.md: create is AT-B1 (ui_create_parameter_group), and a grid rename is the parameter-group-projections AT-C1 derivation, which watches parameter_groups.name and calls the group resync endpoint.

ADRs

The platform series lives in docs/adr/07_Architectural_Decision_Records.md. The per-file series is separate and the numbers collide — see docs/adr/README.md.

ADRDecision
Platform ADR-0046The object-class hierarchy is a single-parent tree — the lineage the SPF *GROUP projection walks
Platform ADR-0047AT-A* / AT-B1 written fields and AT-C1 watch lists stay disjoint, which is why the no-op rename skips its write
Platform ADR-0048domain_id is the public identifier; never a rec… id in a payload
Per-file ADR-0006Canonical parameter keys and values with per-level junctions