Awesome Reviewers

Configurable behavior must be isolated per plugin/consumer instance, and derived/internal values must not be injected into the schema-defined conf object. This prevents cross-request/config leakage and keeps schema validation predictable—especially during deprecations.

Apply:

Example (instance-scoped state instead of module locals):

-- BAD: module-level mutable config shared across instances
-- local use_proto_names = false
-- function protojson:configure(options) use_proto_names = options.use_proto_names end

-- GOOD: store config on the instance
local protojson = {}
protojson.__index = protojson

function protojson.new(options)
  return setmetatable({
    use_proto_names = options.use_proto_names or false,
    enum_as_name = options.enum_as_name or false,
    emit_defaults = options.emit_defaults or false,
    json_names = options.json_names or {},
  }, protojson)
end

function protojson:decode_to_json(msg_type, msg)
  -- use self.use_proto_names etc.
end

Example (don’t mutate conf with non-schema fields):

function OpenTelemetryHandler:log(conf)
  local options = {}
  if conf.resource_attributes then
    options.compiled_resource_attributes = otel_utils.read_resource_attributes(conf.resource_attributes)
  end
  otel_traces.log(conf, options) -- pass alongside conf
end