--- id: w5-release-readiness name: "Wave 5: release readiness (docs, feature matrix, CHANGELOG/README, dry-run)" status: completed depends_on: [w5-decline-matrix, w5-e2e-server, w5-e2e-client, w5-fuzz-harness] scope: moderate risk: low impact: phase level: implementation --- ## Description Everything the publish needs except the publish itself (`docs/plans/implementation.md` §Wave 5, the release-readiness bullet; the alkgit `w5-release-readiness` shape): - **Crate docs**: public-API rustdoc warning-free (default build + `--all-features`; the pre-existing `client_ops.rs` private-link warnings resolved or explicitly dispositioned); the docs-honesty pass: module docs name each surface's postures and known limits (the recorded limits ride the published docs: the `write_all` no-deadline record, the PTY rule-5 fidelity limit, the port-0-only mint wire fact, the no-reconnect-policy boundary, the no-accept-all policy posture); crate-level docs state the feature graph and the fail-closed invariant. - **README.md**, which lands (none exists): what the crate is (the two-direction door), the feature graph + the fail-closed posture (a default build has no capabilities), minimal compile-checked usage examples (a server mount + a dial), the custody/security posture summary (vault-backed keys, no env vars, no secret material on the wire), the license note. - **CHANGELOG.md**: the 0.1.0 entry summarizing the plan's landing per wave (the file exists; the entry lands). - **The feature matrix**: `default` / each feature over it / `--all-features`: test + clippy + doc green (the matrix runner from `w5-decline-matrix` if it landed the vehicle, one command). - **The publish dry-run**: `cargo publish --dry-run --allow-dirty`; the packaged file list verified against the package policy (the `exclude` list: the architecture docs ship as the authoritative contract; the process surface (plans/research/reviews/tasks/ AGENTS.md/`.opencode`) does not); the manifest sanity (version 0.1.0, `rust-version` 1.89, edition 2024, license files present, the pins as ADR-002 records them). - **The freeze inventory**, the list of what the publish makes one-way (the wire-relevant surfaces: the mapping contracts, the honest-advertisement posture, the decline-matrix behavior, the fingerprint string format, the russh pin's wire posture) recorded for the gate's read, because the semver-relevant surface is frozen at the publish, so the gate reads this list against the landed code before `w5-publish` executes. ## Acceptance Criteria - [x] `cargo doc --no-deps` (+ `--all-features`) warning-free or every residual dispositioned; the docs-honesty pass complete (the known-limits records ride the published docs) - [x] README.md landed (what/why, feature graph + fail-closed, compile-checked examples, custody posture, license) - [x] CHANGELOG.md's 0.1.0 entry landed - [x] The feature matrix green (default / each feature / `--all-features`: test + clippy + doc) - [x] `cargo publish --dry-run --allow-dirty` clean; the packaged file list verified against the package policy; manifest sanity recorded - [x] The freeze inventory recorded for the gate ## References - docs/plans/implementation.md §Wave 5 (the release-readiness bullet), §Scope authority (v0.1.0 publishes the crate) - Cargo.toml (the package policy exclude list; the manifest ADR-002 landed), CHANGELOG.md, LICENSE-MIT / LICENSE-APACHE (present) - docs/architecture/ (what ships as the authoritative contract), docs/architecture/decisions/002-russh-pin.md (the pin the manifest records) - /workspace/@alkdev/alkgit (the sibling release shape: README, CHANGELOG, the publish checklist's dry-run posture) ## Notes **Crate docs.** `cargo doc --no-deps` is warning-free on both the default build and `--all-features`. The pre-existing doc-link debt is resolved (not dispositioned): 9 warnings (1 duplicate) at `--all-features`: the `client_ops.rs` private-link class (`crate::tty_map` / `crate::dispatch` / `crate::git_map`, private modules; de-linked to backtick prose), the two `rustdoc::redundant_explicit_links` spans (the `(client_ops::…)` destinations on the `lib.rs` re-export docs and two `[`TunnelChannel`](crate::TunnelChannel)` + `with_tunnel_surface` / `KeySourceError::Decryption` same-item links in `client_accept.rs`/`client_handler.rs`/`error.rs`), the broken `TerminalParamsWire` path (now a resolution-correct target through its wrapped re-export form) and the unresolved `Limits::…` intra-doc link (now `crate::Limits::…`); plus the twin duplicated "report is sent before close" paragraph in `tty_map.rs` removed one. **Docs honesty:** the five recorded limits now ride the *published* docs (the crate-root rustdoc §Known limits: the `write_all` no-deadline record, the PTY rule-5 upstream fidelity limit, the port-0-only mint echo wire fact, the no-reconnect-policy boundary, the no-accept-all policy posture) with their module-doc mirrors verified still in place (`tty_map.rs`, `exit_code.rs` rule 5, `client_accept.rs`/`tunnel_map.rs`, `client.rs` §Lifecycle posture, `host_key.rs`); crate-level docs state the feature graph (each feature's row + the `default = []` decline-only fact + no-feature-implies-another + honest advertisement) and the fail-closed invariant. **Compile-checked examples.** Two `no_run` doctests in the crate-root docs (they run in every matrix build, and the publish task's verification set keeps them compile-checked with zero extra vehicle): a server mount (`ServeConfig::new` → `SshAdapter::new` → `adapter.handle`, on the default build, with sketch key/identity seams returning `Absent`/`None`, prose points at the vault-backed shapes) and a dial (`dial(DialConfig)` → `close()`, the op rows referenced in prose with the feature gate noted; `RejectAll` named as connects-to-nothing by design). README mirrors them. **README.md.** Landed (none existed): what the crate is (the two-direction door, russh owns the wire, door-not-backend), the feature matrix table + the fail-closed posture (a default build serves nothing but declines; unset-config declines; never advertised), the two usage sketches (mirroring the doctests), the custody/security posture summary (vault-backed sources, encrypted at rest, decrypted at use, zeroized; no env vars, no secrets on the wire; publickey-only single attempt; fail-closed host-key default with no accept-all; ACL-gated surface; bounded resources + the known-limits pointer; the decline matrix as contract), the docs pointers, the license note. **CHANGELOG.md.** The 0.1.0 entry landed (founding entry, dated 2026-10-30): the crate story (the two-direction door, the flat fail-closed graph, ADR-003) + the posture statement, then the landed surface wave by wave: the phase 0/1 contract, waves 1–5 (foundations, server stack, server mappings/spine, client direction, validation+release), plus Notes (the sftp decline-only feature fact, the OQ-09 env posture, the russh-pin one-way-door record). Only served surface is listed; the never-features (x11/`auth-agent`/subsystem/`env`) are named as the declines they are. **Feature matrix** (`scripts/matrix.sh`, the one command): all six builds' `cargo test` green (none / git / session / tunnel / sftp-only / `--all-features`, with 108 result-ok reports across the matrix, including both doctests per build), clippy ×2 (`--all-targets -D warnings`, with and without `--all-features`) clean, `cargo fmt --check` clean, `cargo doc --no-deps` clean; plus the fuzz corpus gate (`cargo test --manifest-path fuzz/shared/Cargo.toml`, all 11 invariants green). **Publish dry-run.** `cargo publish --dry-run --allow-dirty` clean, with 76 files packaged and verified (the packaged tree compiles), upload aborted by dry run as expected. The packaged file list verified against the package policy (`cargo package --list`): exactly `src/` (20 files), `tests/` (+ `common/` doubles + `vectors/`), the architecture docs (`docs/architecture/`, the authoritative contract), `README.md`, `CHANGELOG.md`, `LICENSE-MIT` / `LICENSE-APACHE`, the manifests (`Cargo.toml`/`.orig`, `Cargo.lock`, `.gitignore`, `.cargo_vcs_info.json`) and `scripts/matrix.sh` (the verification tooling, not process surface); none of the excluded surface appears (`.opencode/`, `AGENTS.md`, `docs/reviews|plans|research/` / `docs/sdd_process.md`, `tasks/`, `fuzz/` are all absent from the list). **Manifest sanity recorded:** version 0.1.0 (no bump, as `w5-publish` verifies), `rust-version` 1.89, edition 2024, `license = "MIT OR Apache-2.0"` with both license files present, the pins as ADR-002 records them (russh 0.65 `default-features = false` + `aws-lc-rs`; alkcall 0.10; alkvault 0.1; the per-feature optional siblings alktty 0.8.1 / alkgit 0.1.0 / alktunnels 0.4.1), the feature graph exactly ADR-003's, the package-policy `exclude` list in place. **The freeze inventory (for `review-wave-5` and `w5-publish`, the surfaces the 0.1 publish makes one-way; further wire-relevant change is a new ADR + a semver event):** 1. **The mapping contracts**, the channel-type → family-protocol row semantics as landed (`docs/architecture/mapping.md` executed by `dispatch.rs`/`tty_map.rs`/`git_map.rs`/`tunnel_map.rs`/ `client_ops.rs`): the route-1 bridge flow (open-direct → accept-after-fabric-success), the exec-only git grammar + its verdicts, the parse-only dispatch + the translation bridge (chunk framing, the zero-length stdin sentinel, the negotiation-error frame → 255), the exit derivation rules 1–6, the client op-row planes (the family chunk/duplex surfaces, the acceptor registry + payload types, the lifecycle primitives). 2. **The honest-advertisement posture**, the fail-closed invariant as behavior: an unfeatured/unimplemented channel type is declined (never advertised, never half-served); a default build serves declines only; the `sftp` placeholder stays a decline in every build (OQ-13). 3. **The decline-matrix behavior**, the decline classes and shapes: the `OpenDeclineReason` vocabulary as exposed, the spawned-`channel_failure`-then-close serving-path shape, the `ConnectFailed` fabric reject, teardown-at-birth, the token-collision refusal, the config-driven (`seam-unconfigured`/unset-field) declines, the always-`sftp` decline row, as pinned by the matrix suite. 4. **The fingerprint string format**, the `SHA256:` contract format of `crate::fingerprint()` (the crate's single fingerprint path): both the auth bridge's identity resolution and the host-key policy's exact-string pin comparison consume it; changing the format breaks every pin store and is a one-way door. 5. **The russh pin's wire posture**, russh 0.65.0 with `aws-lc-rs` (no compression, `rsa` off, `des`/`dsa` never): the kex/algorithm negotiation surface crosses the crate boundary, so the pin is wire-relevant per ADR-002, and a bump is a deliberate, tested, recorded event. (The `alk/ssh` ALPN pin, ADR-001, is already its own ledger one-way door; the auth surface ships as publickey-only, exactly one attempt.) ## Summary Release readiness landed. Crate docs: warning-free × builds (default + `--all-features`), the 9-warning doc-link debt resolved in place (`client_ops.rs`'s private-link class among them), the docs-honesty pass riding the published crate-root rustdoc (§Known limits: the five recorded dispositions (`write_all` no-deadline, PTY rule-5, port-0-only mint echo, no-reconnect policy, no-accept-all) with module-doc mirrors verified) and crate-level docs stating the feature graph + fail-closed invariant; two `no_run` usage doctests (server mount + dial) keep the README examples compile-checked in every matrix build. README.md landed; CHANGELOG.md carries the 0.1.0 founding entry (wave-by-wave, honest advertisement). The feature matrix is green end to end (six test builds, clippy ×2, fmt, doc) + the fuzz corpus gate (11 invariants). `cargo publish --dry-run --allow-dirty` clean (76 files packaged + verified; the file list checked against the package policy, so that architecture docs ship and the process surface does not; manifest sanity recorded). The freeze inventory (mapping contracts, honest advertisement, decline-matrix behavior, fingerprint format, russh pin posture) is recorded above for the gate's read. Ready for `review-wave-5`; `w5-publish` executes only over a green gate.