Skip to content

V2 phase 1#13

Merged
sssmaran merged 8 commits into
masterfrom
v2-phase-1
Apr 27, 2026
Merged

V2 phase 1#13
sssmaran merged 8 commits into
masterfrom
v2-phase-1

Conversation

@sssmaran

Copy link
Copy Markdown
Owner

Summary

Completes Waylog v2 Phase 1 SDK work across Go and TypeScript.

This PR lands the schema 2.0 foundation, Go v2 SDK core, Go HTTP/framework adapters, delivery transport, dev dual-emit, TypeScript v2 parity, fixture conformance, and Phase 1 docs/examples. Runtime ingest/dashboard/CLI schema-2.0 rewrites remain out of scope for Phase 2.

Major Changes

  • Added schema 2.0 JSON Schema, v1.1 bridge schema, and shared golden fixtures.
  • Added Go pkg/event/v2 validator and fixture parity coverage.
  • Added Go SDK core at pkg/waylog/v2:
    • Init, Shutdown, Stats
    • Begin, Finalize, lifecycle finalizers
    • Step, Fail, Suppress, Explain
    • caps, redaction, dev dual-emit, local writer mode
  • Added Go delivery transport:
    • JSON and NDJSON delivery
    • batching, retry/backoff, queue pressure, shutdown drain
    • rejected-event accounting from ingest envelopes
  • Added Go adapters:
    • net/http
    • outbound RoundTripper
    • chi
    • gin
    • echo
  • Reworked TypeScript SDK to schema 2.0:
    • core lifecycle API
    • AsyncLocalStorage context
    • transport, dev dual-emit, adapters, parity tests
    • Express, Hono, Next.js, NestJS entrypoints
  • Added fixture-driven parity runners and bench gate.
  • Updated README and SDK examples to show the intended v2 usage path.
  • Documented Go allocation-budget debt as post-v2 stabilization work while enforcing current+10% regression gates.

Hardening Included

  • Preserve existing failure anchors across panic, timeout, and abort finalization.
  • Close active Go steps on panic before re-panicking.
  • Keep panic lifecycle anchored to the panicking step.
  • Parse ingest response envelopes and surface rejected events in stats.
  • Shut down replaced Go delivery transports on drained re-init.
  • Align TS reserved WAYLOG_* handling with Go.
  • Keep empty identity fields meaningful in parity normalization.

Verification

  • npm run build
  • npm test
  • go test ./pkg/event/v2/... ./pkg/transport/http/... ./pkg/waylog/v2/... ./pkg/waylog/http/... ./pkg/waylog/chi/... ./pkg/waylog/gin/... ./pkg/waylog/echo/...
  • go test -race ./pkg/waylog/v2 ./pkg/waylog/http ./pkg/transport/http
  • make ci
  • make bench-gate

This lands the Phase 1 Slice 2 foundation on top of the v2.0 schema package:
- add Init, Shutdown, Stats, From, Explain, Step, StepVoid, Fail, NewError, and Suppress
- emit final v2.0 wide events to a writer in local mode
- add request-scoped buffering with MaxSteps, MaxLogs, and MaxBufferBytes enforcement
- degrade oversized requests to header-only output instead of breaking user flows
- synthesize anchors from the first observable failing step
- reject reserved WAYLOG_* lifecycle codes and count misuse in stats
- support suppressed requests as header-only final events
- keep SetField snapshot semantics via deep clone while preserving shallow per-log field merging on the hot path
- add local explainability from the in-memory request buffer
- add tests covering lifecycle behavior, caps, suppression, reserved-code handling, redaction, and concurrency

This slice intentionally does not include HTTP middleware, ingest transport, dev dual-emit, or framework adapters.
This change introduces a new net/http adapter at pkg/waylog/http (package wayloghttp) and wires the existing local-mode SDK core into real HTTP request lifecycles:
- open a v2 request buffer per incoming HTTP request
- preserve inbound W3C traceparent when present
- fall back through x-trace-id, x-span-id, x-request-id, then fresh generated trace/span ids
- seed and maintain fields.http.method, fields.http.route, and fields.http.status
- finalize exactly once across normal return, panic recovery, cooperative cancellation, and watchdog timeout
- recover panics in middleware, emit WAYLOG_PANIC, and return 500 only when headers were not already written
- honor MaxRequestAge with a watchdog that seals first using status=timeout and WAYLOG_TIMEOUT
- increment LateCompletionAfterEmit when a timeout-owned emit wins before handler completion
- preserve ResponseWriter compatibility for Flusher, Hijacker, Pusher, ReaderFrom, and Unwrap

The v2 core is extended so adapters can seal requests with lifecycle-specific terminal states without duplicating event assembly logic:
- add FinalizePanic, FinalizeAborted, and FinalizeTimeout alongside normal Finalize
- add internal lifecycle status synthesis for panic, aborted, and timeout paths
- add SetHTTPStatus for middleware-owned response metadata updates
- add MaxRequestAge accessor for adapter watchdog wiring
- keep suppression precedence intact across panic, cancel, and timeout paths

Tests added and updated:
- core v2 regression coverage for panic/aborted lifecycle sealing and HTTP status field updates
- middleware coverage for ok requests, route selection, write-without-header, trace propagation, trace fallback behavior, panic handling, cancellation, suppression precedence, watchdog timeout, timeout anchor selection, and ResponseWriter interface preservation

This slice intentionally does not add outgoing RoundTripper trace injection, framework-specific adapters (chi/gin/echo), dev dual-emit, or ingest transport. The existing v1 pkg/http adapter remains untouched during the bridge window.
… linkage

This change adds a new transport at pkg/waylog/http that:
- injects W3C traceparent on outgoing HTTP requests
- derives a fresh client span id for each downstream call
- preserves the current request trace id while using the active request span as the parent context
- records downstream linkage back onto the innermost active Waylog step

The v2 core is extended so downstream call metadata survives request assembly:
- replace the active step stack’s string-only shape with a structured active-step model
- carry client step span_id through step close/finalization
- carry structured downstream metadata onto emitted steps[]
- export TraceID, SpanID, and RecordOutgoingSpan for adapter/transport authors
- expose recorded downstream edges through Explain() and its text rendering

Behavioral outcomes of this slice:
- outgoing HTTP requests made inside a Step now emit a traceparent header
- the matching completed step records steps[].span_id with the client span id sent downstream
- the matching completed step records steps[].downstream with service/endpoint/kind metadata
- Explain() now surfaces downstream edges instead of dropping that linkage on the floor

Tests added and updated:
- transport test proving traceparent injection
- transport test proving step span_id + downstream metadata are recorded on the emitted event
- transport test proving no active step means no recorded step linkage
- core explain regression proving downstream edges appear in Explain() and String()
… adapters

Implemented the next Go v2 Phase 1 slices across transport delivery, local developer visibility, and framework expansion.

Delivery transport:
- add a new HTTP delivery client under pkg/transport/http
- support direct single-event POSTs to /v1/events with application/json
- add NDJSON batch flushing with application/x-ndjson
- add two-class queueing for ok vs priority events
- preserve the v2 pressure rule by evicting ok traffic before priority traffic
- drain queued events best-effort during shutdown

SDK wiring:
- wire IngestURL and APIKey into pkg/waylog/v2 initialization
- submit final events to the delivery client when IngestURL is configured
- preserve writer-backed JSONL output as the default local-mode path when IngestURL is unset
- keep emitted/suppressed counters aligned with accepted delivery rather than assuming every queue attempt succeeds

Dev dual-emit:
- enable local dev output when Config.DevMode is true or Env=dev
- emit compact per-log pretty lines at log call time
- emit pretty-printed final wide events at request completion
- keep dev visibility orthogonal to the runtime truth path
- serialize dev output behind a dedicated mutex so log-path emission and finalization do not race

HTTP lifecycle reuse:
- refactor pkg/waylog/http to expose a shared ServeHTTP core
- keep net/http behavior unchanged while making panic/cancel/watchdog/finalize semantics reusable by framework adapters
- add SetHTTPRoute to support frameworks that resolve route templates late

Framework adapters:
- add chi adapter with late route-template capture via chi RouteContext
- add echo adapter that reuses the shared lifecycle while preserving echo route templates
- add gin adapter with a framework-compatible response-writer bridge so handlers still see a gin.ResponseWriter while writes flow through the shared lifecycle wrapper

Testing:
- add transport tests for single-event POST, auth header propagation, NDJSON batching, multi-batch splitting, and queue priority preservation
- add SDK tests for IngestURL transport routing, dev pretty-log output, dev final pretty JSON, and non-dev suppression of local pretty output
- add conformance-style adapter tests for chi, echo, and gin route template capture and shared lifecycle behavior
- keep the existing net/http and v2 core suites passing
Add the v2 Go HTTP delivery path and tighten the SDK/adapters around the new
request lifecycle.

Major changes:
- add v2 HTTP transport delivery with single-event POST and NDJSON batching
- add priority-aware queueing so ok/suppressed events are dropped before error,
  timeout, partial, and aborted events
- add retry handling for transient delivery failures with bounded backoff
- wire SDK IngestURL delivery so final events can go to /v1/events instead of
  local writer output
- add drop/failure visibility through SDK stats
- add shared priority status classification on eventv2.Status

Hardening:
- lock local SDK output writes for race-safe watchdog/late-finalize paths
- reject invalid ingest URLs instead of silently dropping events
- wire MaxInFlightBytes and MaxEventsPerSec pressure knobs
- preserve first HTTP status on duplicate WriteHeader calls
- mark Echo returned errors as Waylog failures
- preserve Chi route templates during panic recovery

Tests:
- add transport retry/drop/pressure tests
- add SDK pressure and invalid config tests
- add adapter regression tests for duplicate headers, Echo errors, and Chi panic routes
Added Phase 1a wrap-up verification for the Go v2 SDK.

Major changes:
- add fixture-driven parity tests for all six v2 golden scenarios
- fix SDK lifecycle semantics required by parity:
  - panic reason matches the fixture contract
  - suppressed events preserve top-level fields
  - timeout and aborted anchors do not add errors[] entries
  - timeout/panic/cancel finalization snapshots active steps before sealing
- add Go benchmarks for middleware, step, logger, and 20-step/50-log assembly paths
- add scripts/bench-gate.sh as a regression gate for Go v2 SDK perf
- add optional make bench-gate target
- document Go allocation budget debt as post-v2 stabilization work

Verification:
- fixture schema validation passes
- v2 parity tests pass 6/6
- Go v2 bench gate passes
- make ci passes
…apters

Rebuild the TypeScript SDK around schema 2.0 and the Phase 1 contract:
- replace the schema 1.1 TS event surface with schema 2.0 wide-event types
- add v2 core APIs: init, shutdown, stats, begin, finalize, lifecycle finalizers, from, step, stepSync, fail, newError, suppress, explain
- implement AsyncLocalStorage-backed request context with standalone Context fallback
- add request buffering for fields, steps, logs, errors, anchor, active-step stack, caps, redaction, rate limiting, and exactly-once finalization
- match Go lifecycle semantics for suppression, panic, aborted, timeout, and active-step timeout snapshots
- add local explain output and dev dual-emit for per-log pretty lines plus final pretty JSON

Add TypeScript v2 delivery transport:
- support ingestUrl delivery to /v1/events
- keep NDJSON batching as the default transport path
- add explicit single-event JSON mode via batchMode=false
- add ok/priority queue partitioning so error/timeout/partial/aborted events are preserved ahead of ok/suppressed events
- add maxInFlightBytes pressure handling, retry/backoff, Retry-After handling, shutdown drain, and delivery/drop stats
- fix shutdown so retryable batches are not dropped immediately during drain
- fix ingest URL normalization so query strings are preserved while /v1/events is applied to the pathname

Update TypeScript framework adapters:
- rewrite Express and Hono adapters to use the v2 core lifecycle
- add Next.js and NestJS entrypoints and package exports
- capture trace propagation, HTTP method/route/status, thrown errors, 5xx failures, watchdog timeout, and suppression behavior
- fix Express synchronous throw handling so finalized requests do not later inflate late-completion stats

Add conformance and parity coverage:
- replace old schema 1.1 TS tests with v2 lifecycle, transport, adapter, and fixture parity suites
- validate all six shared v2 fixture scenarios from testdata/fixtures/v2
- cover transport auth, NDJSON, JSON mode, retry, permanent drops, pressure behavior, and URL normalization
- cover Express/Hono/Next/Nest adapter smoke paths

Update examples and docs:
- refresh README TypeScript usage to the v2 middleware/useLogger surface
- update the TS e2e smoke driver to emit a deterministic schema 2.0 payment-failure request
- clarify that the low-level e2e driver is not the recommended user-facing integration path

Verification:
- cd packages/waylog-ts && npm run build
- cd packages/waylog-ts && npm test
- go test -bench='BenchmarkStepEmptyBody|BenchmarkLoggerInfo' -benchmem ./pkg/waylog/v2/bench -run='^$'
- preserve existing failure anchors when panic, timeout, or abort lifecycle finalizers run
- keep panic-in-step middleware anchoring on the panicking step while still closing the active step before re-panicking
- parse /v1/events ingest response envelopes in Go and TypeScript transports
- expose rejected event counts through Go StatsSnapshot and TypeScript stats()
- shut down the previous Go delivery transport when Init replaces a drained SDK state
- align TypeScript reserved WAYLOG_* error handling with Go by returning undefined and counting the rejection
- tighten Go and TypeScript parity normalization so empty identity strings remain meaningful
- add regression tests for lifecycle anchor preservation, envelope rejection stats, re-init shutdown, step panic cleanup, reserved-code handling, and parity strictness
- update README and SDK examples to reflect the Phase 1 v2 SDK surface
- unignore v2 plan and SDK example docs so Phase 1 closeout docs can be tracked

Verification:
- npm run build
- npm test
- go test ./pkg/event/v2/... ./pkg/transport/http/... ./pkg/waylog/v2/... ./pkg/waylog/http/... ./pkg/waylog/chi/... ./pkg/waylog/gin/... ./pkg/waylog/echo/...
- go test -race ./pkg/waylog/v2 ./pkg/waylog/http ./pkg/transport/http
- make ci
- make bench-gate
@sssmaran sssmaran merged commit 81fa42b into master Apr 27, 2026
1 check passed
@sssmaran sssmaran deleted the v2-phase-1 branch April 27, 2026 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant