Convention is good, agreed, it allows users to have immediate results with modules once they gain a certain level of experience.
On the other hand, there could be non-conventional implementations that could also provide an intuitive UI.
For example, my first module (I didn’t really know what I was doing when I created it) had the CV inputs directly set the param value, this causes the actual controls react to the CV input. Which, whilst not realistic, actually does provide a nice user experience, because they can see the effect that the CV has directly.
Later I wanted to add a more conventional setup, so like you say Bret, I added it to the context menu as an alternative mode to not break existing patches.
Just for reference (although I don’t expect this is exemplary code) here is how I deal with the CV inputs and params in my WAVULIKE module (this is in the body of a loop for the 6 points):
pointValues[v] = params[pointParams[p]].getValue();
pointValues[v] = math::clamp(
((slewType == 0) ? (inputs[pointInputs[p]].getVoltage() / 5.0f) : clickFilters[p].process(args.sampleTime, (inputs[pointInputs[p]].getVoltage() / 5.0f))) +
(knobsOffset ? params[pointParams[p]].getValue() : 0.0f),