Four defects found by dogfooding Speckl against the v0.3 product-layer
spec (FederatedMeetupProduct.speckdl, 74 members):
D1 — CRITICAL: List<T> fields in interface records emitted empty type
Root cause: interface record fields called speckTypeToProto(f.type.name)
which returns '' for List/Map/Set types (their .name is undefined).
Event and state fields had inline List/Map dispatch, but interfaces did not.
Fix: extracted typeExprToProto() shared function that handles all TypeExpr
variants (primitive, ident, list, map, set). All four field-emitting code
paths (interfaces, events, state, transitions) now use it.
D2 — MODERATE: Transition type discriminator field silently dropped
Root cause: parser stores the type field in t.typeDiscriminator (string)
rather than in t.fields array. Generator only emitted t.fields.
Fix: emit typeDiscriminator as 'type' field at number 1, offset other
fields by 1 to avoid collision.
D4 — LOW: Enum variant name collisions across enums in same proto scope
Proto3 requires all enum values unique within enclosing scope, not just
the enum. PENDING in Role and PENDING in OrderStatus collided.
Fix: prefix all variants with upperSnake(enumName) — the proto3 convention.
This also matches the handwritten proto's naming (TRANSITION_TYPE_*).
D5 — LOW: Date in interface fields did not trigger timestamp import
The usesTimestamp check only scanned events and state, not interfaces.
Fix: added interface member check to the timestamp import scan.
D3 (deferred): rc_ typo in spec source silently swallowed by parser.
Parser bug, not generator bug. Filed for future cycle.
Verified: 56/56 tests pass, both FederatedMeetup.speckdl and
FederatedMeetupProduct.speckdl compile to protoc-clean output.