# Revision history for PAGI-Server

0.002004 - 2026-06-28

  Bug Fixes
  - The HTTP/2 tests (t/http2/*.t) skipped only when Net::HTTP2::nghttp2 was
    older than 0.007, but the server treats HTTP/2 as usable only at
    nghttp2 >= 0.008 (PAGI::Server::Protocol::HTTP2::MIN_NGHTTP2_VERSION) and
    when the C library reports itself available. On a smoker with nghttp2 0.007
    the guards passed, the tests ran, and every HTTP/2 session died "nghttp2 not
    installed". The tests now gate on PAGI::Server::Protocol::HTTP2->available,
    the same predicate the server uses, so they skip exactly when the server
    would decline HTTP/2.
  - t/runner.t and t/integration/runner-server.t guarded PAGI::App::File and
    PAGI::App::Directory with the `!defined($v) || $v >= 0.002000` undef-loophole
    that 0.002003 removed elsewhere; a pre-split PAGI install would slip through.
    They now gate on PAGI::Tools, consistent with the other toolkit-dependent
    tests.

0.002003 - 2026-06-28

  Bug Fixes
  - The PAGI-Tools-dependent integration test guards added in 0.002002 did not
    actually skip on a pre-split PAGI install, so a smoker with the old
    distribution still ran t/integration/response-integration.t against the old
    `new($scope, $send)` constructor and died "send is required". The 0.002002
    guards keyed off each body module's own $VERSION with an
    `!defined($v) || $v >= 0.002000` test; the undef branch (meant to allow an
    unversioned in-tree checkout) also admitted the pre-split modules, which are
    likewise unversioned. The guards now gate on PAGI::Tools, a module that
    exists only in the split-era distribution, so a pre-split install has no
    PAGI::Tools and the test skips. PAGI::Tools hardcodes its $VERSION (the body
    modules get theirs injected only at build), so the VERSION(0.002000) check
    is reliable for both installed releases and an in-tree checkout.

0.002002 - 2026-06-27

  Bug Fixes
  - The PAGI-Tools-dependent integration tests now require PAGI::Response (and
    the other toolkit modules they exercise) at version 0.002000 or newer, the
    release that introduced the detached PAGI::Response value API
    (new($scope) + respond($send)). A pre-split PAGI install (<= 0.001023) still
    provides those module names, so the guards previously let the tests run
    against the old `new($scope, $send)` constructor and
    t/integration/response-integration.t died with "send is required" on a
    smoker that had the old distribution installed. The guards now skip on an
    older version while still running against an unversioned in-tree checkout.

  Documentation
  - cpanfile: PAGI-Tools is now on CPAN; note updated accordingly.

0.002001 - 2026-06-26

  Bug Fixes
  - t/lifespan-post-startup-failure.t now skips when the optional
    Future::IO::Impl::IOAsync backend is unavailable, instead of dying at
    compile time. The test use'd Future::IO unconditionally while Future::IO
    is only a `recommends`, so 0.002000 failed to install on a clean smoker
    without it. Now guarded the same way as t/05-sse.t.

0.002000 - 2026-06-26

  Distribution
  - PAGI::Server and bin/pagi-server split out of the PAGI distribution
    into their own distribution. Git history preserved from the original
    repository (https://github.com/jjn1056/pagi).
  - The application runner now ships here as PAGI::Server::Runner (relocated
    from PAGI-Tools). pagi-server stays server-agnostic and threads its
    PAGI::Server-specific options through to the configured server class.

  PAGI 0.3 spec conformance
  - feat: declare PAGI 0.3 conformance — scopes emit version and
    spec_version 0.3.
  - feat(ws/h2): WebSocket Denial Response — an application may send an HTTP
    response instead of accepting the handshake, over both HTTP/1.1 and HTTP/2.
  - feat(h2): HTTP/2 responses now carry a server-supplied Date header.
  - fix(server): populate the WebSocket disconnect reason/code on the
    disconnect event; renamed the queue_overflow close path.
  - feat(server): fire on_complete on clean HTTP request completion, distinct
    from the abnormal-disconnect Future; the lifespan scope state is a
    documented HashRef.
  - fix(server): drop non-spec scope keys — pagi.features from all scopes, and
    pagi.connection from HTTP/2 WebSocket/SSE scopes.

  Backpressure / flow control
  - feat: pagi.transport flow-control handle on HTTP, WebSocket and SSE scopes
    (HTTP/1.1, plus HTTP/2 streaming responses and SSE-over-HTTP/2), exposing
    buffered_amount and edge-triggered on_high_water / on_drain watermark
    callbacks.
  - fix(h2): bound streaming backpressure on the per-stream send queue rather
    than the shared TCP buffer, and break a transport_state reference cycle at
    stream teardown.
  - feat(cli): expose --write-high-watermark and --write-low-watermark on
    pagi-server, threading the write backpressure watermarks through to the
    server constructor (previously settable only via the constructor API).

  Lifespan
  - feat(lifespan): lifespan_mode (auto|on|off) and a matching --lifespan CLI
    flag.
  - feat(lifespan): bound startup with lifespan_startup_timeout (default 30s).
  - fix(lifespan): treat a clean lifespan decline as unsupported rather than an
    error, and log the exception text when a startup raise is treated as
    unsupported.
  - fix(lifespan): surface post-startup lifespan-app failures. A long-lived
    lifespan or background task that died after startup completed was caught by
    a bare eval and silently discarded — no log, server kept running. Such
    failures are now logged at error level; the pre-startup "lifespan not
    supported" auto-detection is unchanged.

  Security / robustness
  - feat(h2): h2_rst_rate_limit — explicit, tunable HTTP/2 Rapid Reset
    (CVE-2023-44487) defense; corrected the max_concurrent_streams POD claim.
  - fix(tls): negotiate TLS 1.3 and compute cipher_suite; drop non-spec TLS
    extension keys.
  - fix(http): return 500 when an application returns without starting a
    response.
  - fix(worker): the master exits non-zero when every worker fails lifespan
    startup, instead of holding the listening socket with nothing serving
    (no zombie master).

  Performance
  - perf: coalesce response writes, add ASCII fast paths, and debounce the
    idle timer.

  Maintenance
  - chore: remove the dead on_error option.
  - docs: documentation-accuracy pass — corrected POD/README claims that
    contradicted the code (Server.pm options, Compliance.pod CL+TE handling,
    the HTTP1 protocol surface, and example outputs) and documented
    previously-undocumented options.

  - For changes prior to 0.002000, see the Changes file of the PAGI
    distribution (versions up to 0.001023).
