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.
Purpose
A parameter group is the authoring grouping that organizes related ParameterKeys for humans — Dimensions, 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
nameis 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.
CreateParameterGroupUseCaseandUpdateParameterGroupUseCaseboth look the candidate name up before writing and returnDuplicateParameterGroupNameErroron a collision with any other group. - A rename to the same name is a no-op:
renamereturns success without recording an event, and the use case skips the Airtable write entirely when no event was recorded. That is deliberate — anAT-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:
| Event | Emitted by | Payload |
|---|---|---|
ParameterGroupChanged | create (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.
| ADR | Decision |
|---|---|
| Platform ADR-0046 | The object-class hierarchy is a single-parent tree — the lineage the SPF *GROUP projection walks |
| Platform ADR-0047 | AT-A* / AT-B1 written fields and AT-C1 watch lists stay disjoint, which is why the no-op rename skips its write |
| Platform ADR-0048 | domain_id is the public identifier; never a rec… id in a payload |
| Per-file ADR-0006 | Canonical parameter keys and values with per-level junctions |