Migration: props.FeatureCmd → props.FeatureID¶
FeatureCmd was named when every feature gated a command. That stopped being
true some time ago — telemetry gates a subsystem, and a forge feature gates an
initialiser, a config section and an asset bundle — so the Cmd suffix had
become actively misleading.
What changed¶
| Before | After |
|---|---|
props.FeatureCmd |
props.FeatureID |
props.Feature{Cmd: …} |
props.Feature{ID: …} |
Nothing else moved. props.Feature, props.FeatureState, Enable,
Disable, SetFeatures, IsEnabled and every feature constant
(props.UpdateCmd, props.InitCmd, …) keep their names.
The constants deliberately keep their Cmd suffix
UpdateCmd, InitCmd, McpCmd and friends are unchanged. They are the
identifiers every downstream tool passes to Enable/Disable, and renaming
them would be a far larger break than the one this buys. Most of them do
still name commands.
How to migrate¶
A mechanical substitution over your Go sources:
grep -rl '\bprops\.FeatureCmd\b' --include='*.go' . \
| xargs sed -i 's/\bprops\.FeatureCmd\b/props.FeatureID/g'
Then, if you construct props.Feature values directly — most tools do not, they
go through Enable/Disable — rename the field:
Your stored configuration and manifests are unaffected¶
The Feature.ID field is still serialised as cmd:
type Feature struct {
ID FeatureID `json:"cmd" yaml:"cmd"`
Enabled bool `json:"enabled" yaml:"enabled"`
}
This is deliberate. Tool.Features is persisted in generator manifests and tool
configs. Renaming a Go identifier is a compile-time event you fix once; renaming
the wire key would silently stop older manifests loading, with no signal until a
regenerate produced the wrong result. So the identifier moved and the tag did
not.
There is no config migration to run, and no manifest to rewrite. A TestFeature_WireKeyIsCmd
guard in pkg/props pins the wire key, so a later tidy-up cannot quietly change
it.
AllFeatures and DefaultFeatures are now functions¶
Both derive from the feature registry rather than being hand-maintained package variables, so a feature declares its default alongside its identity.
DefaultFeatures likewise becomes DefaultFeatures(). Most tools never touch
either — they go through SetFeatures, Enable and Disable, which are
unchanged.
The practical gain: a feature registered by a blank-imported package now appears
in the enumeration. Before this, github and bitbucket were created inline and
listed nowhere, so the feature matrix in every doctor support bundle silently
omitted both.
Generated projects¶
The generator now emits props.FeatureID(...) in scaffolded command files.
Regenerating an existing project updates its sources along with everything else;
a project that is not regenerated keeps compiling against whichever GTB version
it pins.