Decide lazy-default for repeated string|bytes fields

Open design question. For routing/proxy workloads that decode but don't iterate every element, repeated LEN fields could stay as unread ArrayViews until first access. Eager callers pay one extra table alloc; lazy callers skip N per-element string allocations. At 100KB Person, 26+ emails = 26+ string allocations deferrable. Decide: (a) flip default for repeated LEN, (b) gate behind a codegen mode/option, (c) leave eager as default and rely on _decode_lazy. Surface compatibility implications (callers iterate with ipairs today and expect a real array) before deciding.


Decoder: decode_len-style byte-then-varint symmetry in typed decoders

The single-byte peek shortcut in decode_len (wire.lua:410-419) isn't replicated in decode_int32 / decode_uint32 / decode_int64 / decode_uint64 / decode_bool / decode_enum, which always call decode_varint(). Mirror the fast path in each typed decoder so the dominant 1-byte varint case skips a function call. Expected: 5-10% on scalar-heavy decodes. Memory: wire_2byte_varint_cliff (same shape, encode side, already fixed).


Encoder: static type-elision on scalars in mode=full

wire.to_uint64(v) does a type(v) dispatch in three branches (number/cdata/boolean); in mode=full codegen the field's static type is known. Emit UINT64(v) / INT64(v) directly at the call site and let LuaJIT type-guard the trace. Expected: 10-15% on scalar-heavy messages.


Encoder: inline zigzag_encode32 into encode_sint32 (one function call vs two)

encode_sint32(v) = encode_varint(zigzag_encode32(v)) — two function calls. Inline as:

  local function encode_sint32(v)
      local n = bit.bxor(bit.lshift(v, 1), bit.arshift(v, 31))
      -- existing 1-byte fast path
      if n >= 0 and n < 0x80 then return string.char(n) end
      return encode_varint_slow(n)
  end

Same for encode_sint64 (with the int64 zigzag formula).

Tiny win per sint encode — only matters for sint-heavy payloads. Filed for completeness; h8v makes this moot for mode=full (FFI direct writes inline the whole thing anyway). Real applicability: runtime mode encoders.

If h8v lands first, this becomes runtime-mode-only and may not be worth the duplication. Defer the call until h8v ships.


Feature: gRPC server reflection service

PLAN.md section 8 lists gRPC server reflection as a non-goal until after M5. M5 is complete, so keep this as deferred future work. Implement standard reflection once real transport/server use cases require it.


Feature: Tarantool 3.x config integration for schema registration

PLAN.md section 7 mentions a pb.types.<name> declarative config role as a possible Tarantool 3.x integration. Define the use case first, then design how protobuf schemas/descriptors are declared, loaded, validated, and made available to application roles.


Docs: Go plugin API documentation generation

PLAN.md section 6 lists pkgsite for Go docs while Lua docs remain manually maintained Markdown. Decide what Go packages need public documentation and add a repeatable docs target or release note flow for pkgsite/sourcecraft publication.


Feature: gRPC-Web / Connect conformance support

PLAN.md section 8 lists gRPC-Web as not on the v1 path and notes it would be covered by the same Connect conformance harness if added. Track future decision and implementation scope separately from the current Connect-JSON/http_server transport work.


Decision: module path mapping for package-less protos

PLAN.md section 7 notes the current behavior when lua_package and proto package are absent: use the bare filename. Decide whether to keep that behavior or error out to avoid unstable module paths. Update codegen docs and tests accordingly.


Feature: msgpack-flavored encoder for protobuf schemas

PLAN.md section 7 references docs/specs/msgpack_encoding.md. Decide and implement, if still desired, a msgpack-flavored encoder driven by protobuf schemas. Open design points: map keyed by field number vs field name, ARRAY layout for box.space feeders, and MP_TUPLE extension opt-in.


Decision: public C-FFI varint accelerator

PLAN.md section 7 asks whether to expose a public C-FFI varint accelerator. Deferred until benchmarks prove pure-Lua varint code is the bottleneck. Capture benchmark threshold, API surface, and fallback behavior before implementation.


Decision: deterministic map encoding option

PLAN.md section 7 asks whether map encoder should be deterministic by sorting keys. Spec does not require deterministic map order, but some users may need byte-stable output. Decide API shape, likely pb.encode_deterministic or an encode option, and document perf/canonicalization tradeoffs.


Testing: add malformed-input and random-valid fuzz harnesses

PLAN.md section 5 lists fuzz harnesses as not yet automated. Add durable fuzz coverage for malformed wire inputs plus random-valid generated messages. Goal: catch decoder crashes, infinite loops, overlong varints, invalid LEN boundaries, unknown-field preservation bugs, and encode/decode round-trip mismatches beyond fixed fixtures.


Protobuf editions support (deferred)

We advertise FEATURE_PROTO3_OPTIONAL only, not FEATURE_SUPPORTS_EDITIONS. protoc errors out on edition='2023' files with our plugin today. See PLAN.md section 4.6 for the full design — editions replaces proto2-vs-proto3 with per-field FeatureSet annotations (field_presence, repeated_field_encoding, enum_type, utf8_validation, json_format). Practical win is modest: the only knob proto3 doesn't expose today is per-field packed opt-out. Revisit when (a) someone needs per-field packed control, (b) conformance suite gates on editions, or (c) protoc deprecates proto3 syntax hard enough that real users hit the error.


Proto2: MessageSet wire format (deferred)

protobuf-go's protoreflect refuses to load a FileDescriptor declaring 'option message_set_wire_format = true;', calling it a removed proto1 feature. We strip the four MessageSet-flavored nested messages from our vendored test/conformance/proto/test_messages_proto2.proto so the rest of the schema compiles. Real support would require forking protoreflect; deferred until a real Tarantool consumer asks. Track here so we don't lose the context.