Skip to content

release: v0.1.2 polish + docs reconciliation#12

Merged
vnykmshr merged 5 commits intomainfrom
release/v0.1.2-reconciliation
Apr 26, 2026
Merged

release: v0.1.2 polish + docs reconciliation#12
vnykmshr merged 5 commits intomainfrom
release/v0.1.2-reconciliation

Conversation

@vnykmshr
Copy link
Copy Markdown
Contributor

Summary

Final pre-tag pass for v0.1.2. Folds the four sub-80 polish items from PR #10's /code-review pass and reconciles the public surface (README, site, design.md, CHANGELOG) so the docs match the binary at the moment of tag.

Polish (PR #10 carry-over)

  • test(classify): tighten precedence and matrix coverage — drops unreachable cgnat_on_blocked case from TestDecideForecast_Precedence (applyCGNAT runs only when classifyMapping produces Unknown or a multi-success type, so Type=Blocked,CGNAT=true is unreachable). Adds reachable EIM+CGNAT+filtering integration row in TestClassify. Adds wantWarnAbsent to nil_filtering, test1_failed, and rfc_impossible_t2_true_t3_false rows in TestClassify_FilteringMatrix so the warning vocabulary contract cannot leak across cases.
  • test(probe): cover OTHER-ADDRESS Unmap for IPv4-mapped IPv6 — stunserver.Handle Unmaps before encoding, so the existing TestProbe_OtherAddressExtracted only exercised v4-family input on the probe side. New test hand-crafts a response with OTHER-ADDRESS as v6-family carrying ::ffff:198.51.100.1 and asserts Result.Other surfaces as Is4() with string "198.51.100.1:3479".
  • docs(classify): enumerate all Verdict.FilteringTestedAgainst zero-value cases — godoc previously listed two zero-value paths; applyFiltering actually leaves the field zero in four cases (filtering not attempted, ErrFilteringNotSupported, ErrTest1Failed, RFC-impossible T2=true/T3=false). Public-surface accuracy.

Docs reconciliation

  • README — example output drops the stale (v0.1) suffix; §Scope rewritten to describe filtering as capability-driven rather than out-of-scope; JSON-contract list adds the new filtering key; pointer to docs/coturn-setup.md added.
  • site/index.md, site/nat-types.md — same example-output fix; nat-types page gains a paragraph on capability-driven filtering with coturn pointer.
  • docs/design.md — status header now says "v0.1.2 shipped"; v0.2 staged-sequence table adds a Status column and marks v0.1.2 shipped (PRs feat(stunserver): add internal/stunserver package foundation #7docs: add coturn config, setup guide, and v0.1.2 CHANGELOG entry #11).
  • CHANGELOG — promotes [Unreleased] to [0.1.2] with date 2026-04-26, adds fresh empty [Unreleased], updates link refs.

Test plan

  • make test (race, count=1)
  • make lint (0 issues)
  • gofmt -l . clean
  • go mod tidy -diff clean
  • govulncheck ./... no vulnerabilities
  • CI green on this PR
  • After merge: tag v0.1.2 on the merge commit; Pages workflow fires; gh release create v0.1.2 --notes-from-tag
  • Post-tag: VPS spin-up to capture docs/samples/filtering.txt (separate commit on main)

Drop unreachable cgnat_on_blocked case from TestDecideForecast_Precedence
(applyCGNAT runs only when classifyMapping produces Unknown or a
multi-success type, so Type=Blocked,CGNAT=true is unreachable from the
pipeline). Replace with a reachable EIM+CGNAT+ADF case that locks in
CGNAT precedence over restrictive filtering.

Add TestClassify integration row for EIM+CGNAT+endpoint-independent
filtering: the CGNAT honesty rule must override even the most
favourable filtering outcome.

Add wantWarnAbsent assertions to nil_filtering, test1_failed, and
rfc_impossible_t2_true_t3_false rows in TestClassify_FilteringMatrix
so the warning vocabulary contract (filtering_behavior_not_tested vs
filtering_skipped_no_change_request) cannot leak across cases.
stunserver.Handle Unmaps before encoding, so the existing
TestProbe_OtherAddressExtracted only exercises v4-family input on the
probe side. Add a hand-crafted responder that emits OTHER-ADDRESS as
v6-family carrying ::ffff:198.51.100.1 and assert Result.Other.Addr()
comes back as Is4() with string "198.51.100.1:3479".
…ue cases

Existing godoc listed two zero-value paths (filtering not attempted,
server did not advertise OTHER-ADDRESS). applyFiltering also leaves the
field zero for ErrTest1Failed and the (T2=true, T3=false) RFC-impossible
state. Document all four so consumers know zero-value is the only signal
for "no §4.4 sequence ran successfully", regardless of cause.
README, site/index.md, site/nat-types.md previously claimed filtering
classification was out of scope and showed example output with the
"(v0.1)" suffix that no longer matches the binary. Update example output
to current human renderer; revise §Scope to describe filtering as
capability-driven; mention the coturn setup recipe; add the new
"filtering" key to the JSON-contract list.

design.md: mark v0.1.2 as shipped in the v0.2 staged-sequence table and
update the document status header. v0.1.3 (hairpinning) and v0.1.4
(natcheck server) remain planned.

CHANGELOG: promote [Unreleased] to [0.1.2] with date 2026-04-26, add a
fresh empty [Unreleased], update the link refs at the bottom.
@vnykmshr
Copy link
Copy Markdown
Contributor Author

Code review

Found 1 issue:

  1. Dead struct field wantNotTestedWarn bool added to the TestClassify case struct but never set on any case and never read in the assertion loop — its intended check was inlined as if tc.filtering == nil && !hasWarning(...) instead. Global CLAUDE.md says "No dead code -- delete unused code, don't comment it out".

wantWarnings []string // subset assertions
wantWarnAbsent []string // warnings that must NOT be present
wantNotTestedWarn bool // when true, assert WarnFilteringBehaviorNotTested is present
}{
{

Two additional findings scored just below the post-threshold and are flagged here without being attached as blocking — README.md line ~89 ("Hairpinning detection is planned for v0.1.3.") and docs/design.md line 4 ("v0.1.3 (hairpinning) and v0.1.4 (natcheck server) remain planned.") both re-introduce version-target parentheticals into the lean-public-surface files. Project CLAUDE.md says "No roadmap, no version-target parentheticals, no internal process references." Worth a follow-up.

- Drop dead struct field wantNotTestedWarn from TestClassify case
  struct (added in b24c651 but never set or read; the intended check
  was inlined as `if tc.filtering == nil && !hasWarning(...)`).
- Strip "Hairpinning detection is planned for v0.1.3." from README
  §Scope. Public-surface lean rule forbids version-target parentheticals;
  describe hairpinning as out of scope instead.
- Strip "v0.1.3 (hairpinning) and v0.1.4 (`natcheck server`) remain
  planned." from docs/design.md status header. Same rule. The v0.2
  staged-sequence table inside the addendum still carries the planned
  state for those patches.
@vnykmshr vnykmshr merged commit cbe8b60 into main Apr 26, 2026
5 checks passed
@vnykmshr vnykmshr deleted the release/v0.1.2-reconciliation branch April 26, 2026 08:53
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