- Rewrote em dash prose across the whole tree outside docs/reviews/ (the historical reviews stay verbatim, matching the alktunnels and alktty precedent): src doc comments and inline comments (587), docs/architecture (319), docs/research + sdd_process (484), tests (361), tasks (899), fuzz (28), README/CHANGELOG/Cargo.toml (77), AGENTS.md (85), and the .opencode/agents prompts (109) - Fenced content follows the precedent: comments, ASCII-diagram label separators, and template placeholders rewritten; wire data, JSON/BAST documents, byte diagrams, and transcripts survive verbatim; assert, expect, panic, error-display, and format message literals rewritten as prose; no code, fixture, or test data change - src/rfc1928/LICENSE: the two dashes in alksocks' own provenance header rewritten; the MIT legal text untouched - AGENTS.md adds Project Convention 18: no em dashes in prose; varied restructure, no spaced-hyphen substitutes, fenced prose rule, en dash numeric ranges exempt, docs/reviews/ exempt from the greps - tasks/*.md frontmatter: the name values rewritten by the sweep are now quoted (a raw colon inside an unquoted YAML scalar parsed as null); taskgraph validate reports 37 tasks, no issues Verification: cargo test; cargo clippy --all-targets -D warnings; cargo fmt --check; cargo doc --no-deps; fuzz corpus replay (cargo test --manifest-path fuzz/shared/Cargo.toml); wasm check and clippy for wasm32-unknown-unknown with -D warnings; em dash grep over the repo returns matches only in docs/reviews/ and the bast.md BAST JSON data fence
10 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level |
|---|---|---|---|---|---|---|---|
| implementation/fix-rfc1928-posture | Fix: rfc1928 keep-or-cut pass + honest refusal vocabulary (review-002 N-1, N-4) | completed | narrow | medium | component | implementation |
Description
The review-001 keep-or-cut triggers have fired (the producer layer
landed without consuming the anticipated surfaces), and the
in-stream refusal vocabulary mislabels policy refusals as bugs.
One posture pass over both
(docs/reviews/002-protocol-core-implementation-review.md):
-
N-1 (minor): the fork's consumerless machinery. The producer drives
negotiate_authwith&[NoAuthentication]only; the seams carry their own error vocabularies;pump_bidireplacedtransfer. Per the review's disposition:Cut (the producer already replaced them; ADR-013's no-speculative-surface posture wins):
StandardAuthentication+allow_no_auth+auth_method_enums!'s generated enum (src/rfc1928/server.rs:448-482; the macro itself can stay or go with it, as nothing else uses it)skip_auth_this_is_not_rfc_compliant(src/rfc1928/server.rs:185-187; the consumer typestate'sskip_authconfig covers the in-tree need)CheckResult'sOption/Resultimpls (src/rfc1928/server.rs:162-172; keepbool, and re-add with a typed-rejection design if a door ever wants it)
Keep with note (the hand-port-map posture, ADR-013):
ConnectError(constructed nowhere, but the hand-port map's companion; its reply-code mapping is what a future port reuses, which the module doc already says so)transfer/wait_on_tcp(differential-suite-consumed; their semantics stay pinned)SocksServerError::Bug(now consumed by the producer's refusal sites; see N-4 for its display)
The coverage blocks resolve automatically (the accepted-uncovered posture was exactly these blocks). Update the module docs where they name the cut machinery (e.g.
util/stream.rs'sConnectErrornote, theauth_method_enums!doc's "generate a similar enum" line) and the differential suite's comment that referencesStandardAuthentication's method ordering (tests/rfc1928-differential.rs:103; reword to the RFC's ordering rationale, not the cut type). -
N-4 (observation): the task-log refusal vocabulary mislabels policy refusals. Five in-stream refusal sites return errors the wire never sees (the wire got its RFC-faithful reply already; these are log/observability signals only), but the vocabulary lies: the BIND command gate returns
SocksServerError::AuthenticationRejected(an ACL refusal is not "authentication rejected";src/producer.rs:230-233), and four seam refusals returnBug("... refused in-stream")(a policy refusal is not a bug, but the display literally saysBUG: ...atsrc/producer.rs:262-264,302-304,483-485,541-543).. An operator greppingBUG:chases ghosts that are working-as-designed refusals.Fix per the review's sketch: add one variant (
SocksServerError::Refused(&'static str)-shaped) for the in-stream seam refusals and the command gate; use it at the five refusal sites. The wire bytes are untouched (these variants never reach the wire, since the RFC reply went out first). Alternatively keepBugand rename its display, but the dedicated variant is the honest shape; pick one and record it. Mind the fork's provenance posture (convention 17): this is an owned-code extension, so extend the module doc's carried-changes note if the variant list grows.
Tests: the five refusal sites' existing tests assert the mapped
reply codes (unchanged, since the wire is untouched); update any test
asserting the session-error variant at those sites (the harness's
Bug at tests/harness.rs:387 is its own shape; leave it unless it
wants the new variant); one test pinning the new variant's
display/shape if the vocabulary is table-tested elsewhere.
Acceptance Criteria
StandardAuthentication,allow_no_auth, the generated enum,skip_auth_this_is_not_rfc_compliant, andCheckResult'sOption/Resultimpls are cut;boolstaysConnectError,transfer/wait_on_tcp,Bugkept, each with its keep-note current (module docs name the posture)- The differential suite stays green (the cut machinery was not
load-bearing for it; the
:103comment reworded) - The five in-stream refusal sites carry the honest vocabulary (one variant or the renamed display, with the recorded choice); the wire bytes are untouched (the reply-code assertions stay green)
- The fork's provenance notice is extended, not replaced, if the carried-changes note names the new variant (convention 17)
cargo testgreen; clippy/fmt clean; both wasm checks clean;cargo doc --no-depsclean (module docs changed)
References
- docs/reviews/002-protocol-core-implementation-review.md §N-1, §N-4
- docs/reviews/001-rfc1928-full-review.md (the keep-or-cut triggers this closes out; the C-1 misleading-display note)
- docs/architecture/decisions/013-targeted-fork.md (the hand-port map vs no-speculative-surface distinction)
- docs/architecture/decisions/006-access-control.md (the gate: policy refusals are not authentication failures)
- src/rfc1928/LICENSE (the provenance notice; extend, never replace)
Notes
- N-4 shape chosen: the dedicated variant, namely
SocksServerError::Refused(&'static str)with display"Refused: {0}", not theBugdisplay rename. The review's sketch favored the dedicated variant ("the honest shape"), and the vocabulary split is real:Bugstays upstream-verbatim (BUG: {0}, its "should be unreachable" contract intact) while policy refusals get their own honest label. The five sites now readRefused("bind command gate: not allowed"),Refused("dial refused in-stream"),Refused("egress refused in-stream"),Refused("bind factory refused in-stream"),Refused("bind accept refused in-stream"), same&'static strpayload shape asBug, zero wire impact (the RFC reply went out before eachErr). - The harness's
Bugsite was migrated too (the task said "leave unless it wants the new variant"):tests/harness.rs's minimal CONNECT producer returnedBug("dial refused in-stream"), the same working-as-designed refusal shape, so it takes the new variant for vocabulary consistency across the log surface. No test asserts that harness error's variant, so nothing else moved. - The mapping-table test grew the new variant:
SocksServerError::Refusedrides theGeneralFailurefall-through loop into_reply_error_mapping_table(alongsideBug), and a new test pins the display string and the fall-through mapping (refused_variant_display_is_honest_and_ wire_invisible), covering the task's "one test pinning the new variant's display/shape". - Provenance extended, not replaced (convention 17): the
server.rsmodule doc gained a "Post-fork owned changes" paragraph (the cuts, the keep-notes, theRefusedaddition);docs/architecture/rfc1928.mdgained the matching "owned-code post-fork changes" list under the deliberate modifications and alast_updatedline. The bundledsrc/rfc1928/LICENSEnotice already carries the "modifications after the fork point" clause generically, so no change was needed there. - Keep-notes made current:
stream.rs'sConnectErrornote records that the trigger fired and the disposition is keep (was: "cut it then");transfer/wait_on_tcp's differential- suite note lives in theserver.rsmodule doc;Bug's keep-note is the same paragraph (upstream-verbatim, its display untouched). - The differential suite's
:103comment reworded to the RFC-ordering rationale (the server picks by its own preference, more-secure-first), and no cut-type reference remains anywhere. - The
AuthMethodtrait doc was updated for the macro cut (upstream's "use enums for sets" line → a custom selection is a slice of method structs) and the module doc's extraction-time adjustments line dropped the#[macro_export]note (the macro itself is gone).
Summary
Both items landed. N-1 (the cut): auth_method_enums! (the
macro, nothing else used it), StandardAuthentication +
StandardAuthenticationStarted + allow_no_auth,
skip_auth_this_is_not_rfc_compliant, and CheckResult's
Option/Result impls are gone from src/rfc1928/server.rs, since
they were the producer-replaced machinery per ADR-013's
no-speculative-surface posture. Kept with notes: ConnectError
(hand-port companion, stream.rs note updated to record the fired
trigger + keep disposition), transfer/wait_on_tcp
(differential-suite-consumed, semantics pinned there), Bug
(upstream-verbatim, display intact). N-4 (the vocabulary): new
SocksServerError::Refused(&'static str) variant, used at the five
in-stream refusal sites (the BIND command gate + the four seam
refusals) plus the harness's minimal producer; Bug's display is
untouched (a real bug should still read BUG:); the wire bytes are
byte-identical (every reply-code assertion stayed green unchanged).
Tests: the three gate-site session-error asserts moved from
AuthenticationRejected to Refused(...), the four Bug(...)
asserts to Refused(...), the mapping-table loop grew the variant,
and a new display/shape test pins both. Docs: the server.rs
module doc's owned-changes paragraph, the rfc1928.md
"owned-code post-fork changes" list + last_updated, the
stream.rs keep-note, the AuthMethod doc, and the differential
comment. The review-002 N-1 coverage blocks resolve (the cuts were
the accepted-uncovered surface).
Verified: cargo test (356 green across all suites incl.
--all-features), cargo clippy --all-targets -- -D warnings
clean, cargo fmt --check clean, cargo doc --no-deps clean,
cargo check --target wasm32-unknown-unknown +
cargo clippy --target wasm32-unknown-unknown -- -D warnings
clean.