adr-014: the idle-timeout posture — teardown-governed phases, no protocol-layer idle bound
- ADR-014 accepted (review 002 C-2): the pre-command handshake, the BIND quiet wait, and the association lifetime are all teardown-governed; the protocol layer never times out (option 1) - the BIND relationship recorded as same regime (ADR-007 decided one phase's ends by designing BIND; ADR-014 records the inherited resolution — one principle, not two) - the doors' accept-path obligations recorded pre-batch-2 (accept-stage idle bound, per-credential/per-peer caps, accept-queue bounds); revisitable additively (an optional producer-side idle seam would be config, not wire) - spec lines carry the decided posture: wire.md (association-lifetime bullet, no-in-band-control bullet, preamble, frontmatter); producer.md (the open handler, the local-backend section, decision table, frontmatter); overview.md ADR index - one upstream-fidelity correction: upstream's dial timeout maps to 0x06 (TTL expired), not 0x01 as the review sketch suggested - open-questions.md unchanged (C-2 was never tracked there) Verification: cargo test green (357 passed), clippy -D warnings clean, fmt clean, cargo doc clean, wasm check + clippy (wasm32) clean
This commit is contained in:
1 parent
ff3295422c
commit
986bd13ce7
5 files changed
+309
-28
No files matched your search
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: architecture/adr-014-idle-timeout-posture
|
||||
name: "ADR-014 — the idle-timeout posture for the pre-command handshake and the association (review-002 C-2)"
|
||||
status: pending
|
||||
status: completed
|
||||
depends_on: []
|
||||
scope: narrow
|
||||
risk: medium
|
||||
@@ -68,19 +68,19 @@ one.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] ADR-014 exists at
|
||||
- [x] ADR-014 exists at
|
||||
`docs/architecture/decisions/014-<slug>.md`, status accepted,
|
||||
deciding explicitly between the two options (or a reasoned
|
||||
third)
|
||||
- [ ] The BIND quiet wait's ADR-007 relationship is stated (same
|
||||
- [x] The BIND quiet wait's ADR-007 relationship is stated (same
|
||||
regime or a principled difference)
|
||||
- [ ] The doors' DoS posture is recorded (what the assembly layer
|
||||
- [x] The doors' DoS posture is recorded (what the assembly layer
|
||||
must do if the protocol layer does not)
|
||||
- [ ] The affected spec lines (wire.md, producer.md) carry the
|
||||
- [x] The affected spec lines (wire.md, producer.md) carry the
|
||||
decided posture — no implicit residue
|
||||
- [ ] The decision lands before any `local`/`composed` door work
|
||||
- [x] The decision lands before any `local`/`composed` door work
|
||||
(the batch-2 tasks may depend on this one)
|
||||
- [ ] `cargo doc --no-deps` clean if any doc-comment carries the
|
||||
- [x] `cargo doc --no-deps` clean if any doc-comment carries the
|
||||
posture; the full verification sweep green
|
||||
|
||||
## References
|
||||
@@ -99,8 +99,68 @@ one.
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills this during implementation.
|
||||
> Filled by the implementation agent (2026-09-24):
|
||||
|
||||
- **Option 1 won** — the protocol layer never times out; every phase
|
||||
(pre-command handshake, BIND quiet wait, association lifetime) is
|
||||
teardown-governed (EOF / garbage / error sentinels), never
|
||||
idle-expired. No code changed; the posture is recorded.
|
||||
- **The sharpening argument** (why a handshake-only bound is
|
||||
incoherent): every post-reply phase *legally* parks indefinitely on
|
||||
a silent peer — an idle CONNECT tunnel, a quiet association,
|
||||
BIND's quiet wait (ADR-007). The pre-command hold costs exactly
|
||||
what those holds cost (one parked task + one channel entry); a
|
||||
handshake-only bound protects a sliver while the dominant hold
|
||||
stays contractually open, and a bound on both is a full inactivity
|
||||
timeout, which contradicts the landed contracts (association
|
||||
lifetime = channel lifetime; "FTP-length waits stay legal,"
|
||||
ADR-007). The unbounded-time aggregate is a property of every idle
|
||||
session — bounded by the cap regime (ADR-040/041), not by a timer.
|
||||
- **One upstream-fidelity correction to the review's sketch**:
|
||||
upstream's connect-timeout path maps its *dial* timeout to
|
||||
`ReplyError::ConnectionTimeout` → 0x06 (TTL expired), not 0x01 —
|
||||
verified in the reference checkout (`util/stream.rs`) and the
|
||||
forked table (`src/rfc1928/mod.rs`). Recorded in the ADR; relevant
|
||||
only if option 2 is ever built.
|
||||
- **open-questions.md needed no update** — C-2 was tracked as a
|
||||
review finding (tasks/), not as an OQ; no OQ entry exists for it.
|
||||
- **The doors' obligations are recorded pre-batch-2** (the
|
||||
"inherits this bound knowingly" pattern, wire.md §UDP
|
||||
ASSOCIATE's): an accept-stage idle bound (the slowloris sliver —
|
||||
an accepted socket is not a channel, the cap regime does not bound
|
||||
it), per-credential/per-peer session caps (the cred-bearing
|
||||
door's config table, ADR-005, is the knob), and accept-queue/
|
||||
relay-task bounds. Same obligations for the producer-side local
|
||||
backend's accept loop and a composed bind-first listener's front.
|
||||
- **Revisitability**: not a one-way door — a producer-side idle seam
|
||||
is additive (builder config defaulting to `None` = this posture;
|
||||
`tokio::time` already in the wasm-clean subset; timeout = EOF-
|
||||
shaped teardown). Revisit trigger recorded: a deployment with a
|
||||
peer class outside both the cap regime and any door policy, with
|
||||
measured evidence.
|
||||
|
||||
## Summary
|
||||
|
||||
> Agent fills this on completion.
|
||||
ADR-014 landed
|
||||
(`docs/architecture/decisions/014-idle-timeout-posture.md`, status
|
||||
accepted, 2026-09-24), deciding review 002 C-2: **option 1 — the
|
||||
protocol layer never times out**. The pre-command handshake, the
|
||||
BIND quiet wait, and the association lifetime are all
|
||||
teardown-governed; the BIND relationship is recorded as *same
|
||||
regime* (ADR-007 decided one phase's ends by designing BIND; ADR-014
|
||||
decides the rest by recording the inherited resolution — one
|
||||
principle: the protocol layer cannot distinguish malicious silence
|
||||
from a slow legitimate peer, so timeout policy belongs to the
|
||||
deployment-facing layer). The DoS posture is explicit and layered
|
||||
(ACL → per-connection cap → per-identity cap → door/dial policy —
|
||||
the ADR-010 pattern), with the doors' accept-path obligations
|
||||
recorded before any batch-2 door exists. The decision is revisitable
|
||||
additively (not a one-way door). Spec lines updated — wire.md §UDP
|
||||
ASSOCIATE's association-lifetime bullet + the phase-model
|
||||
"no in-band control vocabulary" bullet + the preamble's ADR list +
|
||||
frontmatter; producer.md §The Open Handler's pump description + the
|
||||
local-backend section + the decision table + frontmatter;
|
||||
overview.md's ADR index. No code changes; no OQ update needed
|
||||
(C-2 was never tracked there). `cargo doc --no-deps` clean; full
|
||||
verification sweep green (`cargo test` 348+ green, clippy, fmt,
|
||||
wasm check).
|
||||
Reference in new issue
Block a user