diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b16358e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +node_modules/ +.worktrees/ +Cargo.lock.bak \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..45eff61 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,232 @@ +# AGENTS.md + +Operating instructions for opencode agents working in this repo. opencode +auto-loads this file as instructions, overriding the built-in defaults for +this project. Custom agents in `.opencode/agents/` inherit these rules +unless their own prompts say otherwise. + +## Git Workflow + +**Commit and push when reasonable.** When a change is complete and +verified (build + lint + tests pass), commit and push to `origin/main` +without asking. This overrides the built-in default of "only commit when +explicitly asked." + +Commit in small, focused units — one commit per unit of work (a fix, a +feature, a doc change), not one large commit covering many topics. Push +regularly so work is never stranded locally. + +The workflow: + +1. Make the change +2. Verify: `cargo test`, `cargo clippy --all-targets -- -D warnings`, + `cargo fmt --check`, `cargo doc --no-deps` if docs changed +3. Inspect `git status` and `git diff` before staging — stage only the + intended files, never secrets +4. Write a concise commit message in **conventional commits** style: + `(): ` — types are `feat`, `fix`, `docs`, + `chore`, `refactor`, `test`, `perf`, `build`, `ci`; the scope is + optional. For multi-point changes, use a summary line plus a body with + bullet points and a verification block. +5. `git push origin main` +6. Report the commit hash and the verification summary + +Exceptions — **do not** commit or push without asking: + +- The change is exploratory / speculative (you're not sure the user wants + it kept) +- The user is actively reviewing the diff and may ask for changes +- The change touches wire-relevant or semver-relevant public API (the + `alk/ssh` ALPN pin, the capability feature graph, and the mapping + contracts become stable one-way doors once consumers exist; see the + ADRs in `docs/architecture/decisions/` once they exist) +- You'd be force-pushing, amending a published commit, creating an empty + commit, or skipping hooks + +Never commit secrets, keys, or credentials. If a commit fails or hooks +reject it, fix the issue and create a new commit — do not amend the +failed one. + +Git identity is preconfigured (`glm-5.3-flash `). +Do not change `git config`, skip hooks, or use `git commit -i`. + +## Project Conventions (Rust / SSH adapter crate) + +This is alkssh — the family's SSH adapter (family ADR-003): a thin +wrapper around russh terminating the vanilla-ssh wire and bridging +to/from alkcall channels. The SSH counterpart of alkhttp's adapter +role — the vanilla-ssh front door for vanilla clients. No binary until +an assembly needs one; downstream apps embed the crate and bring their +own deployment. The conventions below apply to all work in `src/` and +`tests/`. They mirror `.opencode/agents/implementation-specialist.md` +§Project Conventions and are repeated here so they apply to every +session, not just spawned implementation agents. + +1. **No comments in code** unless the user explicitly asks. This is a + project-wide convention. Doc comments (`///`, `//!`) are fine and + expected on public API. Inline `//` comments only when the user asks + or when a non-obvious safety/correctness constraint would otherwise + be missed (e.g., "the decline path must run before any per-channel + state is allocated — a leaked channel alloc is a capability leak"). + +2. **Error handling** — `thiserror` for library error types. No panics + in library code. No `unwrap()` or `expect()` outside tests. If you + reach for `unwrap`, the error path wasn't specified — stop and decide + what should actually happen. For poisoned `RwLock`/`Mutex`, use + `unwrap_or_else(|e| e.into_inner())` so a panic in one operation does + not cascade to other operations. + +3. **`tokio` is the async runtime** — all I/O is async. SSH sessions are + long-lived streaming conversations; do not introduce blocking I/O on + the async path. Use `tokio::sync` primitives (`oneshot`, `mpsc`) for + correlation; `parking_lot` for short-held internal locks. + +4. **russh owns the SSH wire** — no in-family SSH framing (family + ADR-003 decision 1). All SSH protocol framing, key exchange, and + channel multiplexing come from russh; the crate's substance is the + glue to/from alkcall and the channel-type mappings. Third-party- + upstream posture: file asks to russh upstream; never silently absorb + a workaround. + +5. **Fail-closed capability features (the binding constraint)** — every + channel-type mapping is a cargo feature. A session opening an + unfeatured or unimplemented channel type is declined with a clean + error — never a half-capability, never a silent fallback (family + ADR-003 decision 3). A default build (no features) has no + capabilities; a git-only build cannot serve a shell, tunnels, or + socks. This is alkforge's ssh endpoint shape. Every disabled + feature's decline path is contract territory and gets tested too — + feature-gated code that is never exercised in a given build rots + silently otherwise. + +6. **Key reuse, no env vars** — keys reuse the alknet `main` key model + (`russh::keys`, authorized-key/KeySource handling — see + `/workspace/@alkdev/alknet-main/crates/alknet-core/src/auth/`) via + alkvault-backed sources (family ADR-003 decision 2). No secret + material on the wire, in plaintext at rest, or in env vars — the + standing family security posture (family ADR-002 decision 5). + +7. **Visible-surface = authorized-surface** — every channel type and + request exposed on the wire is checked against alkcall's + `AccessControl::check(peer_identity)`; ops with + `Visibility::Internal` are never wire-callable. There is no + unauthenticated capability; the fail-closed feature declines are part + of this invariant. This is a spec-level invariant. + +8. **Wire formats are stable one-way doors** — the `alk/ssh` ALPN pin is + its own ADR (ledger rule 1, family ADR-003 decision 4) and, once + published, does not change. The russh version pin is a one-way door + in practice (SSH key exchange/kex algorithm negotiation crosses + crate boundaries); bumps are deliberate, tested, and recorded. + Protocol capability advertisement is honest: never advertise what we + don't serve — an unfeatured channel type is declined, not advertised. + +9. **Bounded resources** — every session carries wall-clock, size, and + channel limits (max concurrent channels, max channel window, session + timeout, auth attempt limits). SSH servers are internet-facing; + unbounded loops and unbounded buffers are bugs. + +10. **License hygiene** — this project is MIT OR Apache-2.0. russh is + MIT/Apache-2.0-compatible; check before adopting any new dependency, + and never copy or derive code from incompatible-licensed reference + projects. Reference code is for reading and facts, never copying. + +11. **Naming** — Rust standard: `snake_case` for functions/variables/ + modules, `PascalCase` for types/traits, `SCREAMING_SNAKE_CASE` for + constants. + +12. **Module structure** — one module per file under `src/`, re-exported + from the crate root (the alktty crate-root pattern). Public API + surface is `lib.rs` re-exports. The mapping table + (channel-type → family protocol) is the crate's spine; each mapping + lives behind its feature and speaks only its family protocol's + types. + +13. **Composability boundary** — alkssh is a door, not a backend: it + terminates vanilla ssh and forwards mapped channel payloads to + family protocol halves (alktty/alktunnels/alksocks/alkgit). It + depends on alkcall types at the wire layer and the mapped crates' + session/client surfaces, and carries no deployment policy — a + downstream app (alkforge) embeds it, enables the features it wants, + and brings identity/ACL configuration. No feature implies another; + the feature graph is independent and flat until architecture says + otherwise. + +## Verification Commands + +Run these before committing. All must pass. + +```bash +cargo test # full suite +cargo clippy --all-targets -- -D warnings +cargo fmt --check +cargo doc --no-deps # if docs changed +cargo publish --dry-run --allow-dirty # before a release +``` + +If feature flags are added, also run `cargo test --all-features` and +`cargo clippy --all-features --all-targets -- -D warnings`. Once the +feature graph lands, each disabled feature's decline path gets a test — +the fail-closed invariant is contract territory on both sides of every +feature. + +## Task files (taskgraph) + +Any file under `tasks/` is a taskgraph task. Frontmatter is required +(`id`, `name`) and its enum fields are **closed sets** (taskgraph +0.1.3): `status: pending|in-progress|completed|failed|blocked` (never +`done` or `finished`), `scope: single|narrow|moderate|broad|system`, +`risk: trivial|low|medium|high|critical`, `impact: +isolated|component|phase|project`, `level: +planning|decomposition|implementation|review|research`. A file without +frontmatter is silently dropped from the graph (validate does not flag +it) — prose-only trackers belong under `docs/`. Run `taskgraph +validate` after writing or editing anything under `tasks/`; full field +semantics live in `docs/sdd_process.md` §"Task File Format" / +§"Categorical Estimates". + +## Lifecycle Status + +The project is in **SDD phase 0** (exploration; docs only — no +architecture committed, no implementation). Family ADR-003 (2026-10-25, +Accepted) records the structural decision already made: russh-wrapped +adapter, no in-family SSH framing, fail-closed capability features, +alknet-main key model via alkvault-backed sources; OQ-08's ordering +question is resolved (alkssh leads alkforge's phase 0) and OQ-08's +remaining scope — the channel-type → family-protocol mapping table +details, the auth design tying russh's authorized-key handling to +alkcall auth, and the `alk/ssh` ALPN pin (ledger rule 1) — is this +repo's phase 0 work. Phase 0 output lands in `docs/research/` (the +phase 0 document is the current work item); `docs/architecture/` + +ADR-001 (the `alk/ssh` ALPN pin) come with phase 1. POC code never +merges to main — two modes: branch mode (POC builds on repo code; git +branch, findings merged into research docs, branch dropped) or +standalone mode (POC independent of repo code; scratch project at +`/workspace/`). POCs have relaxed constraints +(comments/unwrap acceptable) — they are exploration tools, not +production code. + +## Architecture Context + +- `docs/sdd_process.md` — the SDD process (phases, roles, task format) +- family docs: `/workspace/@alkdev/alkfamily/docs/` — + `architecture/decisions/003-alkssh-russh-adapter.md` is the structural + decision this repo builds from (and `002-alkforge-gitea-replacement.md` + explains why: alkforge's git door, fail-closed posture); + `architecture/open-questions.md` OQ-08 holds the remaining scope +- Sibling crates (published, MIT OR Apache-2.0, each with per-repo + AGENTS.md + `docs/architecture/decisions/`): + `alkcall 0.10` (call + channels RPC with ACL; the `alk/ssh` ALPN and + the channel-wire notes are alkcall ADR-004 and ADR-034), + `alktty` (session/pty mapping target), `alktunnels` + (direct/forwarded-tcpip target), `alksocks` (`-D` target), + `alkgit 0.1.0` (git exec/subsystem target), `alkvault 0.1` + (key/secret storage). The alkhttp adapters are the closest structural + analog for the adapter shape. +- alknet `main` key model reference: + `/workspace/@alkdev/alknet-main/crates/alknet-core/src/auth/` + (russh 0.49, `keys.rs` / `server_auth.rs` / `identity.rs`) — the + authorized-key/KeySource construction alkssh reuses; a reading aid + and correctness reference, not a path dependency. +- russh: pin per phase 0 research (the alknet pin — 0.49 — is a data + point, not a decision). \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e82e476 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +All notable changes to this crate are documented here. The format is +based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and +this crate adheres to [Semantic Versioning](https://semver.org/). + +## [Unreleased] + +### Added + +- Initialized: docs-only phase 0 base — SDD process (`docs/sdd_process.md`), + opencode agent definitions, rust crate manifest (lib only, no + dependencies yet), MIT OR Apache-2.0 licensing. The russh pin, the + capability feature graph, and the channel-type mapping table are + phase 0 research output (family ADR-003, OQ-08 remaining scope). \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..165e374 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "alkssh" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..95faee3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,42 @@ +# Single-crate protocol/door crate (the alktty template). No workspace: +# the composition story is deferred — alkssh's substance is the mappings +# (family ADR-003), and phase 0 research settles the russh pin first. +[workspace] +members = ["."] + +[package] +name = "alkssh" +version = "0.1.0" +edition = "2021" +rust-version = "1.88" +license = "MIT OR Apache-2.0" +description = "SSH adapter for the alk family: russh-wrapped vanilla-ssh termination bridged to/from alkcall channels — session/pty, tunnels, dynamic forwarding, git exec/subsystem — with every capability mapping a fail-closed cargo feature (no features: no capabilities)" +repository = "https://git.alk.dev/alkdev/alkssh" +keywords = ["ssh", "russh", "protocol", "alkcall", "network"] +categories = ["network-programming", "asynchronous"] +# The package policy (the sibling crates' convention): the published crate +# ships the architecture docs (the authoritative contract) but not the +# process surface — reviews, research, plans, task files, the working +# agents' config, AGENTS.md. +exclude = [".opencode/", "AGENTS.md", "docs/reviews/", "docs/plans/", "docs/research/", "docs/sdd_process.md", "tasks/"] + +[lib] +name = "alkssh" + +[features] +# The capability feature graph (family ADR-003 decision 3) lands with the +# committed architecture: session (→ alktty), tunnel (→ alktunnels), +# dynamic-forward (→ alksocks), git (→ alkgit), sftp (→ alkfs, deferred). +# The default build carries no capabilities by design — every mapping is +# opt-in and every unfeatured channel open declines fail-closed. +default = [] + +[dependencies] +# Deliberately empty at initialize time — the russh version pin is phase 0 +# research output (alknet main's `russh = "0.49"` is the reference, not the +# answer). alkcall + sibling-crate deps land with the committed architecture. + +[dev-dependencies] + +[profile.release] +lto = "thin" \ No newline at end of file diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..56f9da5 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,192 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name), or refer to, the Work. + (Note: Derivative Works shall not include works that remain separable from, + or merely link (or bind by name) to the interfaces of, the Work and + Derivative Works thereof.) + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to the Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by the Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2025-2026 Alk Development + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..9ee173b --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025-2026 Alk Development + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2b2f272 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,22 @@ +//! alkssh — the alk family's SSH adapter (the alkhttp-style door for the +//! SSH protocol): a thin wrapper around russh terminating the vanilla-ssh +//! wire and bridging to/from alkcall channels (the `alk/ssh` ALPN). +//! +//! No SSH framing is authored in-family (family ADR-003): russh owns the +//! wire, and the crate's substance is the channel-type mappings — +//! session/pty → alktty, direct/forwarded-tcpip → alktunnels, dynamic +//! forwarding (`-D`) → alksocks, git exec/subsystem → alkgit, sftp → +//! alkfs later. Every mapping is a cargo feature; a session opening an +//! unfeatured or unimplemented channel type is declined with a clean +//! error — never a half-capability, never a silent fallback. The default +//! build (no features) is structurally incapable of serving anything but +//! declines. +//! +//! Keys reuse the alknet `main` key model (`russh::keys`, +//! authorized-key/KeySource handling) via alkvault-backed sources — never +//! env vars. +//! +//! This crate is initialized (docs only, SDD phase 0): the dependency +//! surface, the feature graph, and the mapping table are phase 0 research +//! output and land with the committed architecture. See +//! `docs/research/` and family ADR-003.