Files
glm-5.3-flash f4b5f896b4 docs: sweep em dashes from all markdown prose
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.
2026-11-04 20:28:00 +00:00

7.8 KiB

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
w1-config Wave 1: the config surface (serve-config, dial-config, Limits) completed
w1-manifest
w1-key-sources
w1-host-key-policy
moderate low project implementation

Description

Land the pure configuration types both directions implement against, the shapes every later wave's constructors take:

  • Serve-config (server direction, mapping.md/overview.md), the assembly-supplied serving configuration: the OQ-08 fields (shell argv and exec wrapper argv, each Option<Vec<String>>; when unset, its row declines with a clean error, never a fallback, no crate default; the wrapper form is platform-neutral), the IdentityProvider handle (Arc<dyn IdentityProvider>, which the assembly injects; the crate never resolves identities itself), the host-key source handle (the wave-1 key-source seam), the tunnel ChannelClient handle (the route-1 bridge's family-fabric entry, held as an Option; when absent, tunnel rows decline even under the feature), and the Limits. cwd/env in NegotiateRequest are assembly-supplied serve-config values, never wire-derived (OQ-09 posture).
  • Dial-config (client direction, client.md §The dial surface): address, key source (the wave-1 seam; never static keys, never env vars), the HostKeyPolicy handle, and the bounded-resource knobs: keepalive_interval/keepalive_max (15 s / 3 default posture per the reverse-runner evidence), inactivity_timeout, window/packet knobs.
  • Limits: the bounded-resources budget model (overview.md's table): the in-crate max-concurrent-channels cap, exec-parse length caps (consumed by the wave-3 grammar), and the russh knob mapping with documented default postures (max_auth_attempts default 10, sized for the counting none-probe per ADR-004 decision 6; window_size/maximum_packet_size/channel_buffer_size set; inactivity_timeout set, assembly-tunable). Every session carries it; no unbounded loops, no unbounded buffers.

Types only: no russh Config construction (wave 2), no dialing (wave 4). The OQ-08 unset-declines semantics live in the type shape (Option fields + doc contracts), not in construction-time validation.

Acceptance Criteria

  • Serve-config carries the OQ-08 fields as Option with unset-declines doc contracts; no crate default shell/wrapper
  • IdentityProvider, host-key source, and ChannelClient are injected handles; the crate holds no identity/trust policy of its own
  • Dial-config carries key source + HostKeyPolicy + the keepalive/inactivity/window knobs with the documented defaults
  • Limits carries the in-crate caps (channels, exec-parse) and the russh knob defaults (max_auth_attempts 10, keepalive 15 s / 3 client posture)
  • Unit tests cover default construction and the Option-field semantics
  • cargo test, cargo clippy --all-targets -- -D warnings, cargo fmt --check pass

References

  • docs/architecture/overview.md §Public surface, §Bounded-resources policy
  • docs/architecture/mapping.md (OQ-08 rows, the data-plane/limits section)
  • docs/architecture/client.md §The dial surface
  • docs/architecture/open-questions.md (OQ-08, OQ-09 resolutions)
  • docs/architecture/decisions/004-auth-dispositions.md (decision 6: the max_auth_attempts default)

Notes

Landed src/config.rs (ServeConfig, DialConfig, Limits, four posture constants) + lib.rs re-exports. Design decisions pinned against the docs and the alkcall/russh 0.65 source:

  • Limits is the single budget model both directions carry (Copy, plain tuning data): the in-crate caps (max_concurrent_channels 64, max_exec_command_len 8192, with numbers chosen here and documented as assembly-tunable posture constants) plus the russh-knob mapping (max_auth_attempts 10 per ADR-004 decision 6; window_size 2 MiB / maximum_packet_size 32 KiB / channel_buffer_size 100, russh's own defaults kept; inactivity_timeout 600 s carried as plain Duration so the "set (assembly-tunable)" posture is structural, with wave 2/4 mapping it to russh's Option as always-Some; keepalive_interval/keepalive_max Some(15 s)/3 riding inside as the client-direction posture, satisfying the dial-config criterion without a duplicate knob set). russh's rekey Limits stay russh-enforced at their RFC-4253 defaults and are not carried (documented; wave-2 material).
  • Dial-config carries the knobs via its Limits field: the criterion's "keepalive/inactivity/window knobs with the documented defaults" read as the budget model riding the config; the accepted criterion on Limits itself pins that placement, so a second knob set on DialConfig would have duplicated state.
  • No Default for the two configs: the required handles (Arc<dyn IdentityProvider>, Arc<dyn HostKeySource>, Arc<dyn KeySource>, Arc<dyn HostKeyPolicy>) have no crate-defaultable shape (identity resolution and trust are injection-only, per the criterion); ServeConfig::new/DialConfig::new take them, and every tunable is a pub field + Limits::default().
  • **The OQ-08 fields are plain Option<Vec<String>> pub fields
    • doc contracts**; no construction-time validation (the error.rs no-config-error contract). Two request-time check helpers exist (shell_configured/exec_wrapper_configured, plus tunnel_configured) for the wave-2 dispatch to call, reading the Option, never validating.
  • cwd/env (OQ-09 posture) carried on ServeConfig as Option<PathBuf> / BTreeMap<String, String> (empty defaults; never wire-derived; doc contract).
  • channel_client is not feature-gated: alkcall is a base dependency and a field presence is not a capability; the tunnel feature gate applies at wave 2 on top (absent → decline even under the feature; unfeatured → decline too). Doc contract records both gates.
  • Verified the alkcall 0.10 surfaces in-source (registry): core::auth::IdentityProvider is a sync, Send + Sync + 'static trait (dyn-compatible with no async-trait help on alkssh's side; ChannelClient and the NoopIdentityProvider test fixture ride alkcall::channels::client / alkcall::core::auth), and the russh 0.65.0 knob names (window_size, maximum_packet_size, channel_buffer_size, inactivity_timeout, keepalive_interval, keepalive_max, max_auth_attempts) match this module's fields one-for-one.

Summary

Config surface landed: src/config.rs with Limits (in-crate caps: max_concurrent_channels 64, max_exec_command_len 8192; russh knobs: max_auth_attempts 10, window 2 MiB, packet 32 KiB, buffer 100, inactivity 600 s, keepalive Some(15 s)/3, with every number a named posture constant or documented ADR anchor), ServeConfig (OQ-08 shell_argv/exec_wrapper_argv as unset-declines Option<Vec<String>>, OQ-09 session_cwd/session_env, injected IdentityProvider + HostKeySource + optional ChannelClient, limits), and DialConfig (address, injected KeySource + HostKeyPolicy, limits with the keepalive/inactivity/window posture riding inside). No construction-time validation, no crate defaults for the unset rows, no Default for the configs (handles only). Tests: defaults carry the documented postures; Option fields flip independently; handles hold by Arc::ptr_eq; the dial's key source and policy stay fail-closed through the config. Verified: cargo test (36), cargo test --all-features, cargo clippy --all-targets -- -D warnings, cargo clippy --all-features --all-targets -- -D warnings, cargo fmt --check all pass; taskgraph validate clean.