You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Most of this codebase's control flow runs on implicit state machines — state encoded in which handler pointer is installed (nxt_conn_state_t, 25+ instances), in flag combinations (timer enabled/queued/change, h1p bits), or in counter invariants (router nxt_app_t). A code survey found 20 distinct FSMs; only 4 are explicit enums. History shows this is where the bugs live: the chunked-relay proxy fix (nginx#72), the port-IPC reply-path leaks (71fcd89), the CI-only vanishing-headers flake (uninitialized field flags in the resumable parser), and the io_uring engine work's edge-delivery wedges — every one was a missing/undocumented state transition or an ownership gap on an error exit.
The one documentation format with a local track record is docs/io_uring/engine-contract.md (currently on the #31 branch): a code-verified prose contract with per-operation semantics, invariants, and a mismatch inventory — it predicted two real bugs (oneshot accept re-arm, consumed-wakeup readiness loss) before the engine existed. This issue proposes extending that bar to the whole codebase.
Inventory: 20 FSMs ranked by risk (state storage file:line, explicit vs implicit, transition-site dispersion, resources keyed to each state). High-risk: conn lifecycle + 3-phase teardown, port send/recv + shm chunk bitmaps, h1proto client/peer pairs, process/app lifecycle, timers (deferred-change queue).
Format: layered — engine-contract-style prose contracts under docs/fsm/ as the normative spine; a machine-readable YAML transition block per doc; Mermaid diagrams generated from the YAML (never hand-drawn); NXT_DEBUG-gated assertions citing invariant IDs as living documentation (later, small PRs); TLA+/spin for exactly two machines — port messaging and conn close/free — where concurrency meets refcounting.
Audit techniques, ranked by expected bugs-per-effort: transition-completeness audits (every state × event cell gets a verdict — the io_uring wedges were exactly undefined cells); resource-ownership tracing per exit path (the 71fcd89 class); a trace-replay checker that replays debug-build pytest logs against the documented FSM and flags illegal transitions — the only technique that would have caught the CI-only parser flake; targeted fault injection extending the PR SIGSEGV in unit controller process on CentOS 6.9 nginx/unit#57 scaffolding.
Review gate: every doc independently re-derived from code by a second reviewer and diffed; every claim carries file:line. A doc failing verification is itself a finding.
Pilots: (A) unified conn lifecycle + fd-event + timer + accept contract; (B) router↔app port messaging incl. shm chunks and the RPC cancel matrix. Acceptance includes retro-predicting the known historical bugs in each area and a zero-illegal-transition replay of a full debug pytest run.
Relationship to other work
Resource-leak detection at test time (fd/process accounting, orphaned-daemon prevention — the armv7/armhf builder pkill workaround in Alpine's freeunit APKBUILD) is a separate effort planned on PR tools: event-engine A/B benchmark harness (oha + ab) #32; the FSM docs feed it the per-object definition of "leaked" (object exiting in a non-terminal state).
Why
Most of this codebase's control flow runs on implicit state machines — state encoded in which handler pointer is installed (
nxt_conn_state_t, 25+ instances), in flag combinations (timerenabled/queued/change, h1p bits), or in counter invariants (routernxt_app_t). A code survey found 20 distinct FSMs; only 4 are explicit enums. History shows this is where the bugs live: the chunked-relay proxy fix (nginx#72), the port-IPC reply-path leaks (71fcd89), the CI-only vanishing-headers flake (uninitialized field flags in the resumable parser), and the io_uring engine work's edge-delivery wedges — every one was a missing/undocumented state transition or an ownership gap on an error exit.The one documentation format with a local track record is
docs/io_uring/engine-contract.md(currently on the #31 branch): a code-verified prose contract with per-operation semantics, invariants, and a mismatch inventory — it predicted two real bugs (oneshot accept re-arm, consumed-wakeup readiness loss) before the engine existed. This issue proposes extending that bar to the whole codebase.Proposal (full plan in the gist)
Plan: https://gist.github.com/andypost/6d47c38db20a977dc5edc62589010b63
Highlights:
docs/fsm/as the normative spine; a machine-readable YAML transition block per doc; Mermaid diagrams generated from the YAML (never hand-drawn);NXT_DEBUG-gated assertions citing invariant IDs as living documentation (later, small PRs); TLA+/spin for exactly two machines — port messaging and conn close/free — where concurrency meets refcounting.Relationship to other work
docs/io_uring/engine-contract.md+design.md(PR io_uring event engine — Stage 2: completion-mode accept, tiers, hardening #31) become the fd-event section's substrate and get cross-linked, not duplicated.First steps
docs/fsm/conn.md) + the trace checker.docs/fsm/port-messaging.md), then the TLA+ model transcribed from its verified YAML.Findings are expected from the first doc onward — writing the transition table is the audit.