Renames the written-usage rule into practice across the contract surface: docs/ (architecture, research, plans, sdd), tasks/ (all 43 task files, taskgraph validate passes), AGENTS.md, README.md, CHANGELOG.md, and the .opencode/agents/ prompts. Every replacement is a sense-preserving rewrite (colons, semicolons, commas, parentheses, sentence splits, varied), never a mechanical swap; no spaced hyphens were substituted. Enum fields, frontmatter, tables, wire data, and cited identifiers survive verbatim; en dashes inside numeric ranges keep their meaning. Verification: taskgraph validate (43 tasks), repo grep clean (single exempt hit: the verification command's own search pattern in AGENTS.md), cargo test, clippy --all-targets -D warnings, fmt --check, doc all green.
7.8 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| review-wave-1 | Wave 1 gate: the foundations review | completed |
|
narrow | low | phase | review |
Description
The wave-1 review gate, the cheap-place gate of the plan. The config types, the error taxonomy, and the key-source seam are one-way doors in practice: every later task implements against them, and the published crate freezes them. A shape error found here costs a task revision; found after the stack and mappings implement against them it costs churn across both directions.
The gate reads the landed surface against the architecture line by line:
- ADR-002, the pin as declared (russh 0.65,
aws-lc-rsonly, noflate2/rsain the tree, edition 2024, MSRV 1.89); the recordedssh-keyRC exception verified incargo tree. - ADR-003, the feature graph shape (flat, independent,
default = []); the recorded interpretation (per-feature sibling deps land with their first consuming wave) confirmed or corrected. - ADR-004, the fingerprint format invariant (parity vectors green);
the
max_auth_attemptsdefault posture inLimits. - ADR-005, the custody chain (decrypt-at-use,
Zeroizingwrap, distinct failure variants,EncryptedDataopaque, host-key load path, plaintext never persists). - OQ-05, the policy seam (fail-closed default, no accept-all built-in, policy-blind crate).
- OQ-08/09, the serve-config
Option-field semantics (unset → decline, no crate default, no construction-time validation drift). - The error model: no catch-alls; auth declines are dispositions, not errors.
- Docs honesty, or that module docs state what is deliberately not here yet (the stack, the mappings, the client direction).
Verdict: green (wave 2 decomposes, absorbing corrections) or findings booked (remediation before wave 2 decomposes).
Acceptance Criteria
- Every ADR/OQ surface above read and confirmed (or corrected with the correction landed)
- The recorded interpretations confirmed or fixed (sibling-dep timing; the vault-double shape; the policy verdict type)
- Full verification set green (
cargo test,--all-features, clippy, fmt) - Verdict recorded; wave 2 decomposition unblocked or findings booked
References
- docs/plans/implementation.md (wave 1 section + this gate's role)
- docs/architecture/decisions/001…006, open-questions.md
Notes
To be filled by implementation agent
Gate reading (line by line, 2026-10-28)
- ADR-002 ✓, because
Cargo.tomlcarriesrussh = { version = "0.65", default-features = false, features = ["aws-lc-rs"] }; edition 2024,rust-version = "1.89";cargo tree -e normalconfirms norsa, noflate2, noring, and the recordedssh-key =0.7.0-rc.11RC exception riding the russh keys path is present exactly as ADR-002 records it. - ADR-003 ✓, since
session/git/tunnel/sftpdeclared, flat,default = [], nothing implied; the per-feature sibling deps (alktty/alktunnels/alkgit) are not in the manifest; the recorded interpretation (they land with their first consuming wave) confirmed as recorded. - ADR-004 ✓, since
src/fingerprint.rsis the single fingerprint path; both parity suites (tests/fingerprint_parity.rs,tests/doubles.rsfixture rows) are green against thessh-keygen -lf-recorded manifest;Limits::max_auth_attemptsdefaults to 10 with the decision-6 rationale in its doc. - ADR-005 ✓, as the custody chain is in code: one
vault.decrypt→Zeroizing<String>wrap at the adapter seam → one-timedecode_secret_key; the vault's taxonomy reshaped to the five distinct variants (no re-export, no collapse);EncryptedDataopaque in crate code (tests mutate fields only to tamper); host keys decrypt-at-construction viaVaultHostKeySource(empty set →Absent, locked → no key material); rotation-preservation tested; no plaintext persistence anywhere. The known-gap (vault's plainStringreturn) is documented as the ADR-005 decision-3 contract, not silently absorbed. - OQ-05 ✓: the
HostKeyPolicyseam offers aRejectAllfail-closed default; no accept-all built-in (the permissive posture exists only as the double's explicitwith_default(true)choice in tests, which is the correct posture); the crate is policy-blind. - OQ-08/09 ✓:
shell_argvandexec_wrapper_argvare bothOptionwith unset→decline semantics in the type docs; no construction-time validation, no config-error type (the recorded interpretation confirmed, and none was needed);session_cwd/session_envare assembly-supplied, never wire-derived;channel_clientabsent → tunnel rows decline even under the feature. - Error model ✓: five closed variants, no catch-all; the
dispositions-not-errors contract (auth declines, wire declines,
config validation) is written into
error.rs's module docs. - Docs honesty ✓: every module's docs state what is deliberately
not here yet (russh
Configconstruction and the dispatch are wave-2; dial wiring is wave-4; the grammar is wave-3).
Interpretations (flagged for this gate), all confirmed
- Sibling-dep timing: confirmed (see ADR-003 above).
- Vault-double shape, confirmed:
TestVaultwraps alkvault 0.1's own in-memory construction (VaultServiceHandle::new()+unlock_new) rather than re-implementing behind the source trait, so the real error taxonomy and GCM behavior ride every row (the decision is recorded intests/common/mod.rs's module docs). - Policy verdict type, confirmed: accept/reject
bool, pinned to the russh 0.65check_server_key → Result<bool, E>hook shape, with theErrchannel held for wire/IO failures (recorded inhost_key.rs's module docs).
Minor issues found and fixed inline (in this session, same commit set)
Small doc/polish findings; each is a one-to-few-line fix:
cargo doc --no-depsemitted 2 rustdoc warnings (ambiguous[async_trait]intra-doc links, since the crate and the attribute-macro share the name) inkey_source.rsandhost_key.rs→ resolved as plain code spans. The crates' verification set does not run rustdoc, so these had gone unnoticed, which is worth remembering at wave 5's "public-API rustdoc warning-free" gate.key_source.rsHostKeySourcedocs: stray)typo ("on host pin) trust").lib.rscrate docs: stale line ("the dependency surface and feature graph land with implementation start") is now landed; rewritten to state the landed/future split honestly.- Two redundant test lines removed (a discarded pre-probe
try_signinkey_source.rs's usability helper; a redundantNonere-assignment inconfig.rs's independent-flip row).
Nothing found rose to the level of a booked finding, and no shape error in the config types, the error taxonomy, or the key-source seam.
Verification (all green)
cargo test 47/47 · cargo test --all-features 47/47 ·
cargo clippy --all-targets -- -D warnings ✓ ·
cargo clippy --all-features --all-targets -- -D warnings ✓ ·
cargo fmt --check ✓ · cargo doc --no-deps 0 warnings.
Summary
To be filled on completion
Verdict: green. The wave-1 foundations read clean against
ADR-002/003/004/005 and the OQ-05/08/09 resolutions, line by line;
all three recorded interpretations (sibling-dep timing, vault-double
shape, policy verdict type) were confirmed as recorded. Only minor
doc/polish findings surfaced, and they were fixed inline (rustdoc link
disambiguation, a doc typo, a stale crate-doc line, two redundant
test lines), recorded above. No shape errors in the one-way-door
surfaces. Wave 2 decomposition is unblocked; it should absorb the
rustdoc-hygiene lesson (run cargo doc --no-deps on gates), though no fix
tasks are needed.