Commit Graph
25 Commits
Author SHA1 Message Date
glm-5.3-flash 3d0253d981 feat(tunnel): land the -R listen flow + the forwarded-tcpip data leg (w3-tunnel-listen)
The tunnel branch's other half is served for real against published
alktunnels 0.4.1 / alkcall 0.10.1, with POC-3 §C.4 as the template:

- tcpip_forward/streamlocal_forward (+ both cancel forms) map the
  vanilla listen request family-ward through TunnelListener::open on
  the held ChannelClient (bounded inline dial — the global request's
  reply + the &mut u32 bound-port out-param are the hook's); the
  wire bind endpoint rides as the resource string verbatim (OpenSSH
  client-side normalization parity). A reply without the minted
  listen token/bound report declines and reaps its fabric listener.
- the door serves the fabric's inbound tunnel/forwarded opens: the
  serve config gains TunnelListenSeam (the seam-config second
  course-correction — the shared ServingConfig registry the assembly
  wired at from_connection_with_serving); alkssh registers the
  forwarded openable (ChannelCore over a clone of the held client's
  manager) at SshAdapter::new — a failed registration is a failed
  construction (AdapterError::ListenRegistration).
- the forwarded-tcpip data leg: token correlation through the shared
  ListenRouter → the in-crate per-session channel cap at the accept
  surface (the acceptor vocabulary) → Handle::
  channel_open_forwarded_tcpip streaming the listen request's own
  args + the actually-bound port (sshd parity) with
  TunnelForwardedParams.peer as the originator → pump_bidi(ssh,
  fabric). Correlation-miss → teardown-at-birth, never a half-open
  SSH channel. Unix arrivals ride forwarded-streamlocal@openssh.com.
- bounded bookkeeping: the per-session listener map packet-loop-only
  with a dedicated max_concurrent_channels-ceiling counter; the
  route map bounded by construction (mints at accepted listens,
  removed at cancels + session teardown — the handler's Drop).
- the harness grew the client-side accept hook
  (server_channel_open_forwarded_tcpip/_streamlocal,
  acceptor-driven) + a hand-rolled tracing subscriber; 18 contract
  rows + both real-tool smokes (ssh -L, ssh -R + curl) green in
  tests/tunnel_mapping.rs; the wave-2 stub listen rows migrated per
  build (unfeatured / seam-unconfigured).

Verified: cargo test across default/git/session/sftp/tunnel and all
combos + --all-features; clippy -D warnings (default, all-features,
combos); cargo fmt --check; cargo doc --no-deps clean;
taskgraph validate (26 tasks).
2026-10-29 04:24:50 +00:00
glm-5.3-flash 6443feac3e feat(tunnel): land the route-1 bridge — direct-tcpip + streamlocal served for real (w3-tunnel-direct)
- The route-1 bridge (ADR-006 decision 1, the POC-3 stage-C recipe
  re-landed as contract): per accepted `direct-tcpip` /
  `direct-streamlocal` open, the target/substrate are constructed from
  the SSH open arguments and the spawned task runs
  `TunnelSession::open_direct` over the held `Arc<ChannelClient>` →
  accept only after the fabric open succeeds → `take_halves()` pumped
  against the taken channel (`pump_bidi`) — the open hook returns fast;
  a fabric failure answers the explicit `ConnectFailed` reject (the
  wave-2 stub's reason surviving as the real decline; the stub retired
  from the direct rows, kept on `forwarded-tcpip` for w3-tunnel-listen).
- The cap across the fabric window (recorded): the admission is taken
  at the hook and held across the fabric open; a fabric failure
  releases the count inside the spawned task — the admitted-but-
  rejected shape no `channel_close` can ever fire for. `ChannelCap`
  became a mutex-backed `Arc`: admissions stay packet-loop-only,
  releases have exactly two disjoint sites (close hook, bridge task),
  both saturating.
- The identity ride recorded (the `w2-auth-bridge` parked item): the
  alkhub `hub_leg.rs` one-time-set precedent is a serving-side set; the
  client-side `take_call_connection()` seam is rejected for this door
  (one-shot detach of the shared assembly handle's open surface — a
  fortiori the relay note's "wrong for hubs"); the identity the fabric's
  `AccessControl::check` consults is the dial identity (CF-005), the
  composition is assembly policy, and the door structurally refuses
  anonymous serving (`no-identity`, unreachable on the wire). Upstream
  ask booked for the gate.
- The OQ-11 runtime-Unix gate: `direct-streamlocal` compiles wherever
  `tunnel` compiles; off-Unix a clean open-decline before any fabric
  call (dial-call witness at zero), on-Unix the real bridge.
- Decline classes recorded: policy → `AdministrativelyProhibited`
  (unfeatured/cap/`no-identity`); cannot-bridge → `ConnectFailed`
  (failed fabric open, absent handle under the feature, invalid
  target, off-Unix streamlocal); the event vocabulary gains
  `invalid-target` and `unix-unavailable`.
- The optional dep lands: `alktunnels 0.4.1` (pin re-verified against
  crates.io — max stable, MIT OR Apache-2.0, rust_version 1.88, alkcall
  0.10.1 exact), wired `tunnel = ["dep:alktunnels"]`, `local` never
  enabled.
- The fabric double (`tests/tunnel_mapping.rs`): the POC-3 §C.4
  in-process recipe — `ChannelsAdapter` + `InstallChannelZero` + the
  alktunnels openables + a hand-rolled dial/dial-fail seam (in-process
  duplex targets keyed by the rendered string; the smoke's dial is real
  TCP). Rows: both-substrate serve round trips, fabric-failure,
  cap refusal + release + recovery, the fabric-ACL composed-gate
  witness, the CF-006 identity witness, the OQ-11 gate, and the
  `ssh -L` + curl real-tool smoke (conditional-skip posture, ran green).

Verification: `cargo test` rows green per feature build (default,
tunnel, git, session, git+session, tunnel+git, tunnel+session,
--all-features); `cargo clippy --all-targets -- -D warnings` ×2
(default + --all-features) clean; `cargo fmt --check`; `cargo doc
--no-deps` 0 warnings; `taskgraph validate` (26 tasks).
2026-10-29 03:23:20 +00:00
glm-5.3-flash b1e569d1a8 feat(session): land the session mapping — the translation bridge + the exit derivation (w3-tty-session)
The biggest single-row surface of the spine: pty/shell/pipe-exec serve
through the published alktty seam (drive_session_pre_negotiated) over a
translation bridge, re-landing POC-3 stage D as contract:

- src/tty_map.rs (session feature): the bridge (SSH data → Chunk::stdin
  through a bounded mpsc + framing task; SSH EOF → the zero-length
  stdin sentinel — verified against alktty's pump semantics; stdout →
  data; stderr → extended_data(1); exit chunk → the derivation
  contract), the locally-built negotiation (OQ-08: shell argv verbatim,
  wrapper ++ [cmd], cwd/env session-side, ttymodes → the reserved {}
  modes JSON), and the spawned serving path.
- serve_tty_row: driven chunks→SSH inline so the exit report is the
  path's final act (status before close, ADR-006 decision 4); two
  cancel signals (per-channel watch fired by channel_close, connection
  teardown fired by SessionHandler::Drop) abort the alktty session
  task — the ADR-056 kill-on-drop contract is the cancelled session's
  cleanup.
- Derivation contract rules 1–6 in derive_exit + the crate-local
  signum→name table: −N → exit-signal(name), −1 → exit-status(255),
  core_dumped never, unmapped negatives → 255, the PTY-path rule-5
  fidelity limit documented; wire rows pin the shapes.
- Negotiation-error frames (alktty's 0x00-length-prefixed error
  framing) → negotiation-failed serving decline + exit-status(255) +
  close — the one could-not-start claim this door makes (nothing ran).
- Control rows: window_change/signal → the per-channel BridgeSurface
  (bounded mpsc, try_send, never awaited on the packet loop); signal
  names verbatim (no decline shape — fire-and-forget); pre-serve
  resizes update the stored pty params (final size wins).
- Unset-declines (OQ-08) keep the git row's serving-path shape
  (failure then close, spawned): shell-unconfigured /
  wrapper-unconfigured / seam-unconfigured; pipe-less shell SERVES
  pipe-mode (the recorded vanilla-sshd posture); env_request decline
  unchanged (OQ-09).
- tests: the hand-rolled TtyBackend shim + ownership witness doubles;
  serving rows through the harness, the unset-field decline matrix,
  derivation rows on the wire, negotiation-failure rows, the identity
  ride asserted live at the seam, the kill witness; the real-tool
  smoke — OpenSSH -tt against a real PTY via dev-dep alktty local
  (test graph only), skip-with-reason posture. Wave-2 stub rows
  migrated to the new decline reasons (dispatch_core, observe).

Verification: cargo test (113) / --features session (149) / git (142) /
tunnel (115) / --all-features (161) — all green; cargo clippy
--all-targets -- -D warnings ×5 feature configs; cargo fmt --check;
cargo doc --no-deps ×3 builds clean; taskgraph validate.
2026-10-28 20:29:59 +00:00
glm-5.3-flash 7aac2d11a2 feat(git): land the git mapping — the exec grammar + the alkgit dispatch (w3-git-mapping)
- dispatch: the full exec grammar replaces the wave-2 skeleton probe
  (quoted/unquoted paths, the .git normalization decision, unknown-
  service / service-only decline-with-reason class; the probe's unit
  rows migrate with their pinned verdicts preserved)
- git_map: the git row dispatches serve_duplex_resolved over the
  channel duplex (repo id validated, never resolved; the exit-status
  mapping 0/1 decided per POC-3 §A.5; status before close from the
  spawned task), with the resolved identity riding the seam
- handler: the store-and-take channel handoff (stored at the open,
  taken in the spawned serving task, released at close) and the
  max_exec_command_len pre-parse cap
- config course correction: GitSeam carries the assembly-supplied
  alkgit Limits (the ADR-009 budget alkgit's contract assigns the
  assembler)
- tests: tests/git_mapping.rs (byte-level process-mode advertisement,
  ls-refs round + exit 0, the collapsed-denial byte-order + exit 1,
  the identity-ride authorize-gate witness, the packless CAS push,
  the grammar/cap decline rows, the sequential-serve store row, and
  the real-tool git 2.43 clone smoke over a TCP mount with a
  skip-with-reason posture); dispatch_core/observe rows updated to
  the new decision set; tests/common/git_doubles.rs (the hand-rolled
  recording alkgit quartet)

Verification: cargo test (default), --features session, --features
git, --all-features; clippy -D warnings ×2; fmt --check;
cargo doc --no-deps; taskgraph validate
2026-10-28 20:03:10 +00:00
glm-5.3-flash 58d0b86ec5 feat(observe): land the decline-path event vocabulary (w3-decline-tracing)
The wave-2 gate's booked finding: observability on the decline paths.
`tracing` rides the manifest per the ADR-002 toolkit but nothing in
src/ emitted — a decline's "reason" was only the routing decision
documented per build.

- src/observe.rs: the event vocabulary, adopting the family posture
  read from alktty/alktunnels/alkcall/alkhttp (free tracing fns,
  message-last lowercase, flat fields; no info!/trace!, no macros,
  no spans): feature_build + row + channel_id + decline_class
  (open/request/serving/auth) + reason + exec_route (exec rows);
  declines at debug, the serving-path failure arm the vocabulary's
  one warn
- handler.rs: every decline site emits — auth dispositions
  (non-ed25519 / fingerprint-unresolved / the four unimplemented
  methods), open-level declines (unfeatured / never-feature /
  cap-exceeded / tunnel connect-failed stub), request-level
  capability declines (exec route-aware, subsystem, env, x11, agent,
  the -R listen forms), and the seam-stub serving declines with the
  spawned-path lifecycle (started / ended / failed — the shape the
  wave-3 mappings inherit)
- tests/observe.rs: the event-presence pin — a hand-rolled global
  capture subscriber (the recorded test convention; no event-capture
  precedent exists in the family), field-matching rows across the
  default/git/session/tunnel/--all-features builds, and the safety
  scan (no username, no fingerprint ever in an event)
- helper-level exact shapes pinned in src/observe.rs unit rows

Verification: cargo test (default, --features git/session/tunnel,
--all-features all green), clippy x2 --all-targets -D warnings,
fmt --check, cargo doc --no-deps 0 warnings, taskgraph validate.
2026-10-28 17:50:49 +00:00
glm-5.3-flash 270365ea4c feat(config): land the wave-3 per-feature family-seam handles (w3-seam-config)
- ServeConfig gains cfg-gated SessionSeam / GitSeam Option fields
  (whole-Option struct per seam — the shape decision recorded in the
  task notes): unset → the owned rows decline even though the feature
  is on, no construction-time validation
- SessionSeam carries the alktty backends map + backend selector +
  ownership provider; GitSeam carries the alkgit backend quartet +
  caller-owned pipeline semaphore + push_options_negotiated
- optional deps alktty 0.8.1 / alkgit 0.1.0 wired feature-to-dep
  (pins verified against crates.io: licenses, MSRV, shared alkcall
  resolution); gix-hash 0.28 as dev-dep only (alkgit does not
  re-export ObjectId for the trait doubles)
- per-feature construction/unset-declines/Debug rows in config.rs;
  accessors session_seam_configured / git_seam_configured; docs state
  what each seam handle carries

Verified: cargo test (per-feature + --all-features), clippy ×2
(-D warnings), fmt, cargo doc --no-deps, cargo tree feature isolation
(git-build: no alktty; session-build: no alkgit), taskgraph validate
2026-10-28 16:12:03 +00:00
glm-5.3-flash d1f755f2d9 docs(tasks): decompose wave 3 — the server mappings
Six implementation tasks + the gate under tasks/implementation/,
chained sequentially (the mappings replace stubs in the same Handler
impl and share the decline-matrix test binaries):

- w3-seam-config: the serve-config's per-feature seam handles
  (alktty backends/ownership/selector; the alkgit quartet/pipeline/
  push-options flag) + the optional sibling deps — wave 3's first
  course correction to the wave-1 config surface
- w3-decline-tracing: the wave-2 gate's booked finding — the
  decline/serve-path tracing vocabulary, landed before the mappings
- w3-git-mapping: the full exec grammar replaces the wave-2 probe +
  the serve_duplex_resolved dispatch + the store-and-take handoff
- w3-tty-session: the translation bridge + the exit-derivation
  contract (rules 1-6, the signum table)
- w3-tunnel-direct: the route-1 bridge (accept only after the fabric
  open succeeds) + set_identity propagation + the capacity-across-
  fabric-window mechanics
- w3-tunnel-listen: the -R listen flow + the forwarded-tcpip data
  leg (the POC-untested leg; the stop-and-book provision)
- review-wave-3: the gate

The plan carries the wave-3 decomposition record with four
interpretations flagged for the gate (the serve-config course
correction, the already-discharged server-side sftp bullet, the
w3-tunnel-listen open mechanics, the booked-items' wave-3 homes).
taskgraph validate: 26 tasks, clean.

Sibling pins verified against crates.io at decomposition time:
alktty 0.8.1 / alkgit 0.1.0 / alktunnels 0.4.1 / alkcall 0.10.1.
2026-10-28 12:32:13 +00:00
glm-5.3-flash 5b2654f492 docs(tasks): close the wave-2 review gate — verdict green
Gate reading (commits b90e89b..196289f) against the architecture line
by line: ADR-001 mount contract, ADR-002 Config construction,
ADR-003 feature gates, ADR-004 dispositions, ADR-006 constraints,
mapping.md skeleton decline matrix per build, bounded resources, and
the harness — all confirmed. All four flagged interpretations
confirmed as recorded.

Fixed inline before committing (task-file hygiene only):

- w2-loopback-harness, w2-dispatch-decline-core: acceptance boxes
  checked once verified against the landed rows/runs
- w2-bounded-resources: stale placeholder lines removed
- review-wave-2: verdict recorded

Booked finding (next wave's decomposition): decline-path
tracing/observability — the reason a given wire decline carried is
currently docs-only (tracing unused in src/).

Verification: cargo test 104 rows green; --all-features green;
clippy ×2 -D warnings green; fmt clean; cargo doc 0 warnings;
taskgraph validate 19 tasks.
2026-10-28 11:53:51 +00:00
glm-5.3-flash 196289f5ad feat(handler): enforce the in-crate concurrent-channel cap at the open surface (w2-bounded-resources)
- new private channel_cap module: per-session active-channel count;
  admit (check+increment at accept sites) / has_room / saturating
  release, single-writer (inline packet-loop hooks), unit-tested
- handler wires the cap at every channel_open_* hook: the session
  accept path admits-and-counts at the accept point; the tunnel rows
  cap-gate before the seam stub (a counted-but-unopened stub would
  leak the cap); x11 never consumes a count; the count releases
  through the new channel_close hook
- dispatch::cap_exceeded_open_decline -> AdministrativelyProhibited
  (the assembly's policy ceiling; OpenSSH MaxSessions parity)
- bounded-resources contract rows: cap reached -> clean decline,
  close -> recovery open succeeds (wire-order deterministic),
  zero cap refuses without poisoning, exhausted cap answers the
  tunnel row with the cap reason; max_auth_attempts verified
  behaviorally (within-ceiling failures keep the advertisement, the
  past-ceiling attempt is the NoMoreAuthMethodsAvailable teardown);
  window/packet/buffer/inactivity knobs recorded as covered by the
  config-mapping tests
- max_exec_command_len stays carried, not enforced (wave-3 grammar)

Verification: cargo test (default), --features session / git /
tunnel / --all-features, clippy --all-targets (-D warnings, also
--all-features), fmt --check, cargo doc --no-deps - all green
2026-10-28 11:40:29 +00:00
glm-5.3-flash 2e5a7c9cee feat(serve): land the spawn-and-return plumbing + exit/status mechanics (w2-spawn-return)
- src/serve.rs (new): the ADR-006 decision-4 mechanics in code —
  spawn_serving_path (the one choke point; nothing awaited inline)
  and report_exit_status_then_close (exit-status before close via
  the cloned Session::handle()), #[doc(hidden)] contract-test
  re-exports; a unit row pins spawn-returns-while-pending.
- src/handler.rs: the four session-row seam stubs became spawned
  serving paths (failure-then-close unchanged; stubs are plain fns —
  an async stub holding &Session across the spawn is non-Send); open-
  level declines and the tunnel seam stub stay inline by class, per
  the new module-doc section.
- tests/spawn_return.rs (new): two end-to-end wire rows — the client
  observes exit-status(7) strictly before close and after the handler
  returned; the handler-returns-fast row routes follow-up traffic
  while the serving path is still gated (POC-3 deadlock inversion).
- tasks/implementation/w2-spawn-return.md — completed with notes.

Verification (all green): cargo test; per-feature dispatch matrices
(--features git/session/tunnel/sftp, --all-features); cargo clippy
--all-targets/-all-features with -D warnings; cargo fmt --check;
cargo doc --no-deps (no warnings); taskgraph validate.
2026-10-28 11:04:17 +00:00
glm-5.3-flash 68d3723f6a feat(dispatch): land the parse-only dispatch + the fail-closed decline core (w2-dispatch-decline-core)
- src/dispatch.rs: the ExecRoute decision, the skeleton exec-parse
  probe (service prefix + path shape; wave 3 replaces with the full
  grammar), the wire-reason shapers (AdministrativelyProhibited for
  unfeatured/never-feature opens, ConnectFailed for the tunnel seam
  stub), 7 probe unit rows
- src/handler.rs: channel_open_* gates per the feature graph (session
  ∨ git; tunnel; x11/auth-agent never), parse-only exec_request
  dispatch before any allocation, session-row routes, request-level
  declines (subsystem all-names with the sftp OQ-13 and git named
  classes, env per OQ-09, x11/agent, the four listen requests), the
  named wave-3 seam stubs; decline-first-alloc-never structural;
  module docs carry the decline-core contract incl. the inherited
  auth-agent-open upstream note
- tests/dispatch_core.rs: 26 Contract-stamped decline-matrix rows per
  feature build driven through the loopback harness (none / git-only /
  session-only / tunnel-only / all-features + shared never-feature
  rows)
- tests/common/harness.rs: extended helper vocabulary (tunnel/x11
  opens, pty/env/x11/agent requests, listen requests) — discharges
  the w2-loopback-harness live-rows note
- tests/loopback_harness.rs: the skeleton decline-only session-open
  row cfg-pinned to the featureless builds it describes

Verification: cargo test (91 rows, default build); per-feature
dispatch_core rows (git 11 / session 10 / tunnel 4 / all 8 / sftp 3);
cargo test --all-features; cargo clippy --all-targets -- -D warnings
(and --all-features); cargo fmt --check; cargo doc --no-deps
2026-10-28 09:04:42 +00:00
glm-5.3-flash 3b77193e85 feat(tests): land the loopback harness — the in-process contract-test vehicle (w2-loopback-harness)
- tests/common/harness.rs: the recorded transport decision (tokio
  duplex pair + russh connect_stream; recorded over TCP loopback for
  determinism, no-port portability) and placement decision (sibling
  of the wave-1 doubles, the crate's contract-test vehicle convention)
- the client-side posture from the doubles: MemHostKeyPolicy bridged
  into russh's check_server_key (HarnessClientHandler, decision input
  byte-equal to the wave-4 dial wiring's), the Limits keepalive/
  inactivity posture (client_config), fixture-key auth helpers
- thin helpers: authenticate_publickey + remaining_methods,
  open_session_channel (open-failure reason observed in the Err),
  request_exec/shell/subsystem, next_message / await_exit_status /
  await_close, drive → LoopbackSession with clean unmount
- acceptance proof in tests/loopback_harness.rs: 6 contract-stamped
  rows, incl. the full in-process connect → fixture-key auth →
  authenticated-session observation (host-key decision log +
  observed decline reason) and the fail-closed host-key decline

Verification: cargo test (81 pass), cargo clippy --all-targets
-- -D warnings, cargo fmt --check, taskgraph validate — all green.
2026-10-28 08:42:15 +00:00
glm-5.3-flash 2202149fc0 feat(auth): land the ADR-004 dispositional auth bridge (w2-auth-bridge)
- auth_publickey: ed25519-only gate → single fingerprint path →
  resolve_from_fingerprint → accept-with-identity (stored per-
  connection, read by wave 3) / reject fail-closed; the gate is
  explicit-over-inherited (ADR-002 decision 4) and precedes resolution
- auth_publickey_offered: explicit accept-and-delegate (counting
  stays honest, POC-1)
- auth_none / auth_password / auth_keyboard_interactive /
  auth_openssh_certificate: four explicit family-contract declines
- username carried by no hook — resolution is fingerprint-only (OQ-03)
- SessionHandler constructible via #[doc(hidden)] re-export (the
  w2-server-mount note's widening); resolve_bridge structured out of
  the #[non_exhaustive]-arg hooks so contract tests drive the bridge
  core directly
- tests/auth_bridge.rs: 21 rows — wire rows over the real adapter
  mount (accept, fail-closed reject, username independence, revoke
  between attempts, none/password/certificate declines) + direct
  rows over the wave-1 doubles
- cert fixture (throwaway ca + alpha-cert.pub) recorded in
  fingerprints.txt; MemHostKeySource double in tests/common

Verification: cargo test (76 across the suite), --all-features,
clippy --all-targets (both feature sets, -D warnings), fmt --check,
doc --no-deps, taskgraph validate — all green
2026-10-28 08:33:57 +00:00
glm-5.3-flash b90e89b600 feat(server): land the SshAdapter mount + russh Config construction (w2-server-mount)
- SshAdapter:🆕 decrypt-at-construction host-key load (ADR-005
  decision 6) — locked / absent / decryption / unknown-version /
  decode all refuse with AdapterError::Construction(KeySourceError
  preserved), no adapter; an empty key set refuses as Absent even
  from a custom source.
- russh 0.65 server Config built from ServeConfig: methods exactly
  {publickey} (MethodSet from [MethodKind::PublicKey] — honest
  advertisement, ADR-004 decision 4); host keys ride Config::keys;
  Limits knobs (window_size, maximum_packet_size,
  channel_buffer_size, max_auth_attempts) one-for-one;
  inactivity_timeout always Some (bounded-resources posture). All
  other knobs stay russh's default posture: rekey Limits (RFC-4253
  defaults, russh-enforced), auth_rejection_time, server_id
  (russh default — recorded), server keepalive (client-direction
  posture only).
- SshAdapter::handle: ADR-001 mount — generic duplex stream in,
  run_stream per stream, run to completion (Result<(), AdapterError>;
  no ALPN/relay code; the serving loop is spawned inside russh, so
  ADR-006's spawn-and-return holds without double-spawning).
- SessionHandler skeleton (pub(crate)): per-connection
  russh::server::Handler with type Error = AdapterError; every hook
  at the inherited fail-closed default; carries Arc<ServeConfig> for
  w2-auth-bridge / w2-dispatch-decline-core.
- AdapterError (error.rs): Construction + Wire (From<russh::Error>)
  — the wave-1 error-model's reserved wave-2 shape.
- Tests: advertisement-exactly-publickey; knob mapping (tuned +
  default postures); key-set parity; construction failure matrix;
  EOF-on-mount; wire smoke (russh client over duplex: full KEX,
  fail-closed auth decline, exactly the {publickey} method list on
  the wire).

Verified: cargo test (61 across suites), cargo test --all-features,
clippy --all-targets -- -D warnings (default + all-features),
fmt --check, cargo doc --no-deps, taskgraph validate.
2026-10-28 07:51:50 +00:00
glm-5.3-flash 18ef55c60d docs(tasks): decompose wave 2 — the server stack
Six implementation tasks + the gate under tasks/implementation/,
chained sequentially (the auth hooks, dispatch, and channel cap all
edit the same per-connection Handler impl):

- w2-server-mount: SshAdapter::handle mount + russh Config
  construction from the serve-config (honest advertisement, host-key
  decrypt-at-construction, the Limits knob mapping) + the Handler
  skeleton at fail-closed defaults
- w2-auth-bridge: the ADR-004 dispositions (ed25519-only explicit
  decline, fingerprint-only resolution, explicit declines for every
  non-publickey method)
- w2-loopback-harness: the in-process client/server contract-test
  vehicle over the wave-1 doubles
- w2-dispatch-decline-core: parse-only dispatch + the fail-closed
  decline core, contract-tested per feature build
- w2-spawn-return: the structural constraint pinned by test + the
  exit-reporting mechanics via the cloned Session::handle()
- w2-bounded-resources: the in-crate concurrent-channel cap at the
  handler surface
- review-wave-2: the gate

The plan carries the wave-2 decomposition record with four
interpretations flagged for the gate (skeleton-level git probe,
declining routing stubs, the adapter error surface, the harness
transport choice). taskgraph validate: 19 tasks, clean.
2026-10-28 07:38:04 +00:00
glm-5.3-flash a19cdc4832 docs(tasks): close the wave-1 review gate — verdict green
Review task record: the line-by-line ADR/OQ gate reading, the three
flagged interpretations confirmed (sibling-dep timing, vault-double
shape, policy verdict type), the minor inline fixes, and the green
verification summary. Wave 2 decomposition unblocked.
2026-10-28 07:22:24 +00:00
glm-5.3-flash 214690b9c2 test(doubles): land the wave-1 in-memory seams + unified ed25519 fixtures
The `w1-test-doubles` task: the in-memory seams every later wave's
contract tests run against, behind their production seams.

- tests/common/mod.rs — the doubles, test-only (nothing reachable from
  lib.rs, no feature): MemIdentityProvider (registered fingerprints ->
  alkcall Identity resolutions over the IdentityProvider trait; token
  path resolves none per ADR-004), TestVault (a wrapper over alkvault
  0.1's shipped in-memory construction — resolving the flagged
  vault-double question: wrap, not re-impl), MemHostKeyPolicy
  (exact (host, fingerprint) rules + explicit default verdict,
  fail-closed by default, inspectable decision log), and the fixture
  table. Module docs record the location/vault/fixture decisions and
  the row/stamp discipline (greppable Contract stamps).
- tests/vectors/ — one unified fixture set: four ssh-keygen-minted
  ed25519 keypairs (committed .key + .pub + fingerprints.txt recorded
  from ssh-keygen -lf, OpenSSH_9.6p1). The previous inline PEM
  constants in src/key_source.rs were rejected by OpenSSH itself
  (russh-only decodable); all keys were re-minted and the overlapping
  vector set retired — one fixture set now serves the parity tests,
  the custody round-trip, and every later auth/mapping test
  (src-unit tests share it via include_str!).
- tests/doubles.rs — the end-to-end rows: register -> resolve,
  seal -> source -> decode (+ locked/absent/tampered postures),
  host-key set in order, policy verdicts honored-and-logged.
- tests/fingerprint_parity.rs and src/key_source.rs tests moved onto
  the shared fixture files; src changes are #cfg(test) only.

Verification: cargo test (33 + 9 + 5 green; --all-features also green),
cargo clippy --all-targets -- -D warnings clean, cargo fmt --check
clean, taskgraph validate ok (12 tasks).
2026-10-28 07:09:17 +00:00
glm-5.3-flash 949d0bbbe4 feat(config): land the configuration surface (serve-config, dial-config, Limits)
- ServeConfig: OQ-08 shell_argv / exec_wrapper_argv as
  Option<Vec<String>> with unset-declines doc contracts (no crate
  default shell/wrapper); OQ-09 session_cwd/session_env
  (assembly-supplied, never wire-derived); injected
  Arc<dyn IdentityProvider> + Arc<dyn HostKeySource> handles;
  optional Arc<ChannelClient> route-1 handle (absent -> tunnel rows
  decline even under the tunnel feature); Limits.
- DialConfig: address + injected Arc<dyn KeySource> and
  Arc<dyn HostKeyPolicy> handles + Limits.
- Limits: the bounded-resources budget model both directions carry —
  in-crate caps (max_concurrent_channels 64, max_exec_command_len
  8192) and the russh-knob mapping with documented postures
  (max_auth_attempts 10 per ADR-004 decision 6; window 2 MiB /
  packet 32 KiB / buffer 100; inactivity 600 s always-set shape;
  keepalive Some(15 s)/3 client posture).
- Types only: no russh Config construction (wave 2), no dialing
  (wave 4); no construction-time validation — unset-declines lives
  in the type shape (error.rs no-config-error contract).

Verified: cargo test (36), cargo test --all-features, clippy
(all-targets, -D warnings, default + all-features), fmt --check.
2026-10-28 06:57:52 +00:00
glm-5.3-flash 4d529dbacf feat(key-source): land the vault-backed key sources (ADR-005 custody in code)
- Two injected-handle seams: KeySource (dial-config, decrypt-at-use ->
  one PrivateKey) and HostKeySource (serve-config, decrypt-at-construction
  -> the Config::keys set); async_trait object-safe, the HostKeyPolicy
  handle shape
- Crate-provided ADR-005 implementations: VaultKeySource (injected
  vault handle + Option<EncryptedData>, None -> Absent) and
  VaultHostKeySource (record set, empty -> Absent) over the shared
  decrypt_and_decode chain: vault.decrypt -> Zeroizing<String> seam
  wrap -> one-time decode_secret_key(plain, None)
- EncryptedData opaque in src/ (no key_version interpretation); vault
  error taxonomy reshaped into the five-variant KeySourceError matrix,
  never collapsed; plaintext never persists
- 12 in-module tests on the real in-memory alkvault handle: round-trip
  (fingerprint-identical ed25519 key that signs), full failure matrix,
  locked host-bootstrap refusal, lock-mid-session lifecycle,
  v2->v3 rotation identity; three committed throwaway PEM fixtures

Verified: cargo test (23 + 4 parity), cargo test --all-features,
clippy -D warnings (default + all-features), fmt --check, taskgraph
validate
2026-10-28 06:45:56 +00:00
glm-5.3-flash 149f11d4b2 feat(host-key): land the HostKeyPolicy seam (OQ-05, policy-blind)
- HostKeyPolicy trait: async, dyn-compatible (Arc<dyn> handle, the
  alkcall injected-handle pattern) — decide(&self, &PresentedHostKey)
  -> bool with host/port/fingerprint as the decision input
- Verdict type pinned to the russh 0.65 check_server_key shape:
  bool is the trust decision; decline reasons stay with the policy
  (declines are dispositions, not errors). Flagged for the wave-1 gate
- Built-in default RejectAll: fail-closed reject-all (russh's default,
  kept); no accept-all option exists in the crate
- async-trait 0.1 added for the dyn-compatible async handle
  (alkcall-precedented; tree-deduped). Flagged for the wave-1 gate
- Tests: default rejects; custom verdict honored; both through the dyn
  handle; the whole presented context reaches the policy

Verified: cargo test (14), cargo test --all-features, cargo clippy
--all-targets -- -D warnings, cargo fmt --check, taskgraph validate
2026-10-28 06:40:40 +00:00
glm-5.3-flash 635e82b54b feat(fingerprint): land the single fingerprint path + ssh-keygen parity vectors
- src/fingerprint.rs: alkssh::fingerprint wraps the ssh-key re-export
  (HashAlg::Sha256) — the crate's only fingerprint computation and
  formatting site (ADR-004 decision 1's contract invariant)
- tests/fingerprint_parity.rs: 4 committed ed25519 fixtures with
  ssh-keygen -lf-recorded fingerprints (OpenSSH 9.6p1, independent
  issuer); blobs cross-checked against the vectors manifest
- verified: cargo test, clippy (default + all-features, -D warnings),
  fmt; taskgraph validate clean
2026-10-28 06:27:49 +00:00
glm-5.3-flash d85299df38 feat(error): land the fail-closed key-source error taxonomy
- KeySourceError with exactly five variants (Locked, Absent,
  Decryption, UnknownKeyVersion, Decode) — ADR-005 decision 4's
  failure matrix as distinct shapes, the vault taxonomy reshaped
  never collapsed; no catch-all, no Other/Unknown
- payload shapes pinned: Locked/Absent payload-free;
  Decryption/UnknownKeyVersion carry the vault's opaque messages;
  Decode carries a message so the RC-pinned ssh-key error type
  never enters the public API (flagged for the wave-1 gate)
- each variant doc-commented with ADR-005 semantics + fail-closed
  consequence; module stays engine-blind (no vault/russh types)
- no From<VaultServiceError>: non-mappable vault variants would
  force a collapse; w1-key-sources maps explicitly at its seam
- exhaustive-match + Display/Debug/Clone unit tests

Verified: cargo test (default + all-features), cargo clippy
--all-targets --all-features -- -D warnings, cargo fmt --check,
cargo doc --no-deps, taskgraph validate
2026-10-28 06:22:52 +00:00
glm-5.3-flash 78ae905b21 build(manifest): land wave-1 dependency set and ADR-003 feature graph
- russh = "0.65", default-features off, aws-lc-rs only (ADR-002:
  no flate2, no rsa; tree RC-free except the recorded ssh-key
  0.7.0-rc.11 pin riding the russh keys path)
- alkcall 0.10, alkvault 0.1 version-pinned; no path deps
- standing toolkit: tokio, thiserror, tracing, parking_lot, zeroize
- edition 2024, rust-version 1.89
- ADR-003 feature graph: session/git/tunnel/sftp, default = [],
  flat and independent — features gate nothing yet (wave-2
  decline core is the first consumer)
- task w1-manifest completed; notes/summary filled

Verified: cargo tree (no rsa/pkcs1/flate2), cargo test, cargo test
--all-features, cargo clippy --all-targets -- -D warnings (default +
all-features), cargo fmt --check, taskgraph validate
2026-10-28 06:20:20 +00:00
glm-5.3-flash 0b1bc284fa docs(plans): add wave-based implementation plan; decompose wave 1
- docs/plans/implementation.md: five-wave decomposition of the
  architecture (foundations -> server stack -> server mappings ||
  client direction -> validation & release), following the alkgit
  sibling pattern (decompose-implement-gate rhythm, per-wave
  decomposition records, review gates at wave boundaries)
- scope authority: v0.1.0 publishes the crate; assembly wiring stays
  out; sftp decline placeholder is shipped behavior
- wave 1 decomposed into eight task files under tasks/implementation/
  (manifest, error model, key sources, host-key policy, fingerprint,
  config surface, test doubles, review gate) with recorded
  interpretations flagged for the gate

Verification: taskgraph validate (12 tasks, no cycles); cargo test,
clippy -D warnings, fmt --check green
2026-10-28 06:13:26 +00:00
glm-5.3-flash 644269b258 docs(architecture): scaffolding + ADR-001 (alk/ssh ALPN pin, Proposed)
- decisions/001: pins alk/ssh to one contract — raw vanilla-SSH byte
  stream, endpoint = SshAdapter::handle; payload-blind relay restated
  per alkcall ADR-042; phase 1 serves edge termination only; relay/
  browser legs stay compatible by construction (consumers deferred,
  OQ-01). Status Proposed — ledger-rule-1 acceptance pending review.
- open-questions.md: 13 OQs seeded from POC findings (3 resolved by
  evidence: username disposition, vault role split, reconnect policy;
  4 deferred with blockers: relay consumer, cert auth, env allowlist,
  sftp/alkfs); deferred/failed trackers filed under tasks/architecture/
  for each deferred(scope) OQ (taskgraph validate: 4/4 valid)
- README.md index: current state, doc table, planned docs, lifecycle
2026-10-26 06:11:42 +00:00