## Summary
gqlgen's `graphql.DefaultRecover` prints a recovered resolver panic and `debug.PrintStack()` to stderr, so the log collector stores every stack line as a separate, level-less entry (~60 entries per panic in production).
Adds `otelsetup.Recover` (`func(ctx context.Context, err any) error`, a `graphql.RecoverFunc` for gqlgen v0.17.95):
- logs the panic as **one** ERROR record via `slog.Default().ErrorContext` (the default logger services set up through `logging.SetupLogger`), with `panic`, `stack` (`debug.Stack()`) and `path` (GraphQL field path, when available) attributes
- records the error on the active span (`RecordError` with stack trace, `SetStatus(codes.Error)`)
- returns the generic `internal system error` gqlerror to the client, without the panic text
Services install it with `srv.SetRecoverFunc(otelsetup.Recover)`.
## Test plan
- `TestRecover`: error and non-error panic values; asserts the generic gqlerror, no panic text leak, exactly one ERROR log record with panic/stack attributes, and span status Error with an `exception` event carrying message and stacktrace (in-memory `tracetest.SpanRecorder`)
- `go test -race ./...` passes, `prek run --all-files` passes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01H6eVuR4Yt3m7TbDTDwyZJi
Reviewed-on: #206