diff --git a/tasks/architecture/adr-026-transport-interface-separation.md b/tasks/architecture/adr-026-transport-interface-separation.md new file mode 100644 index 0000000..776dde8 --- /dev/null +++ b/tasks/architecture/adr-026-transport-interface-separation.md @@ -0,0 +1,63 @@ +--- +id: architecture/adr-026-transport-interface-separation +name: Write ADR-026 — Transport/interface separation (three-layer model) +status: pending +depends_on: [] +scope: moderate +risk: high +impact: project +level: implementation +--- + +## Description + +Write ADR-026 establishing the three-layer model: Transport (Layer 1), Interface (Layer 2), Protocol (Layer 3). This is the most architecturally significant new ADR — it redefines SSH as an interface (not a transport) and enables the DNS control channel, raw framing, and future WebTransport as (Transport, Interface) pairs. + +The three layers: +- **Layer 1: Transport** — produces byte streams. TCP, TLS, iroh, DNS (as byte carrier), WebTransport. A `Transport` still produces `AsyncRead + AsyncWrite + Unpin + Send`. +- **Layer 2: Interface** — consumes a `Transport::Stream` and produces call protocol events (sessions). SSH is an interface. Raw framing (4-byte length prefix + JSON EventEnvelope) is an interface. DNS control channel is a (DNS transport, raw framing interface) pair. +- **Layer 3: Protocol** — carries semantics. Call protocol events, operation registry, service calls. Protocol is agnostic to both Transport and Interface below it. + +A **connection** is always a (Transport, Interface) pair. The valid combinations are enumerated: +- (TLS, SSH) — standard alknet tunnel +- (TCP, SSH) — plain SSH tunnel +- (iroh, SSH) — P2P SSH tunnel +- (DNS, raw framing) — DNS control channel +- (WebTransport, SSH) — browser SSH tunnel (future) +- (WebTransport, raw framing) — browser call protocol (future) +- (TCP, raw framing) — direct call protocol, local mesh + +Key changes from current architecture: +- SSH is an interface, not a transport. Currently deeply embedded in ServerHandler. +- The `TransportKind` enum gains `Dns` and `WebTransport` variants (initially tags only). +- Raw framing (4-byte BE length prefix + JSON) is an interface without SSH wrapping. +- DNS control channel carries call protocol frames directly — it does NOT wrap SSH inside DNS. + +This ADR requires careful review because it's the foundation for Phase 1.8 (Interface Abstraction), which is the most invasive code change. + +## Acceptance Criteria + +- [ ] `docs/architecture/decisions/026-transport-interface-separation.md` exists +- [ ] ADR follows established format +- [ ] Context explains why SSH is currently tangled with transport and why separating them matters (enables DNS, raw framing, WebTransport without SSH) +- [ ] Decision states: three layers; SSH is Layer 2 not Layer 1; Transport trait produces byte streams unchanged; Interface trait consumes Transport::Stream and produces call protocol sessions; connection = (Transport, Interface) pair; valid pairs enumerated +- [ ] Shows the Interface trait signature (consume stream, produce sessions) +- [ ] Lists the valid (Transport, Interface) combinations +- [ ] Consequences: enables DNS control channel without SSH wrapping; enables raw framing for service mesh; SSH becomes pluggable; ServerHandler is refactored into SshInterface +- [ ] DNS control channel carries call protocol directly (NOT SSH inside DNS) — explicitly stated +- [ ] References: research/core.md DNS section, integration-plan.md Phase 1.8 + +## References + +- docs/research/core.md — transport layer, DNS transport section +- docs/research/integration-plan.md — Phase 1.8, three-layer model, DNS as (DNS transport, raw framing interface) +- docs/architecture/transport.md — current Transport trait (unchanged at Layer 1) +- docs/architecture/server.md — current ServerHandler (will become SshInterface) + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/architecture/adr-027-crate-decomposition.md b/tasks/architecture/adr-027-crate-decomposition.md new file mode 100644 index 0000000..7295415 --- /dev/null +++ b/tasks/architecture/adr-027-crate-decomposition.md @@ -0,0 +1,57 @@ +--- +id: architecture/adr-027-crate-decomposition +name: Write ADR-027 — Crate decomposition +status: pending +depends_on: + - architecture/adr-029-identity-core-type +scope: moderate +risk: medium +impact: project +level: implementation +--- + +## Description + +Write ADR-027 defining the crate decomposition for the alknet project: what crates exist, what each contains, and crucially what the dependency graph looks like (which must be acyclic). + +Crate structure: +- **alknet-core**: transport, SSH, call protocol, config, auth types, identity, OperationSpec, Interface trait. Depends on: russh, tokio, irpc (feature-gated), serde. Does NOT depend on: alknet-secret, alknet-storage, alknet-flowgraph. +- **alknet-secret**: BIP39, SLIP-0010 Ed25519 HD key derivation, AES-256-GCM, SecretProtocol irpc service. Depends on: bip39, ed25519-bip32 (or rust-bip32-ed25519), aes-gcm, sha2, irpc. Does NOT depend on: alknet-core, alknet-storage. +- **alknet-storage**: SQLite-backed metagraph, identity tables, ACL graph, honker integration, StorageProtocol irpc service. Depends on: rusqlite, honker, petgraph, jsonschema, irpc. Does NOT depend on alknet-core (but implements alknet-core's IdentityProvider trait via the trait, not a crate dep). Does NOT depend on alknet-secret (but references EncryptedData type format). +- **alknet-flowgraph**: FlowGraph over petgraph, operation graph, call graph, type compatibility. Depends on: petgraph, serde, jsonschema. Does NOT depend on: alknet-core, alknet-storage, alknet-secret. +- **alknet-napi**: Node.js native addon. Depends on: alknet-core. +- **alknet** (CLI binary): Assembles everything. Depends on: alknet-core, alknet-secret (feature), alknet-storage (feature), alknet-flowgraph (feature), toml. + +The narrow interface points: `Identity` type, `IdentityProvider` trait, and `OperationSpec` are in alknet-core. External crates implement core traits or serialize to formats core understands. + +This ADR must also address the irpc feature flag question (OQ: resolved — irpc is behind a feature flag in alknet-core, independent in other crates) and the storage/secret irpc dependency question (resolved — each crate depends on irpc independently). + +## Acceptance Criteria + +- [ ] `docs/architecture/decisions/027-crate-decomposition.md` exists +- [ ] ADR follows established format +- [ ] Context explains why decomposition is needed: core shouldn't depend on heavy services; different deployment topologies need different subsets; circular dependencies prevent clean builds +- [ ] Decision states: the six crates, their contents, and their dependencies +- [ ] Includes the dependency graph ASCII art from integration-plan.md +- [ ] States the narrow interface points: Identity, IdentityProvider, OperationSpec +- [ ] States that irpc is a feature flag in alknet-core and an independent dep elsewhere +- [ ] States that alknet-storage implements IdentityProvider via the trait (not a crate dependency on alknet-core) +- [ ] States that alknet-storage references alknet-secret's EncryptedData wire format (type-level compatibility, not crate dep) +- [ ] Consequences: core is lean; services are pluggable; no circular deps; deployment topology determines which crates to include +- [ ] References: integration-plan.md dependency graph, ADR-029 + +## References + +- docs/research/integration-plan.md — Phase 2, dependency graph +- docs/research/core.md — alknet-core contents +- docs/research/services.md — service protocols +- docs/research/storage.md — alknet-storage contents +- docs/research/flow.md — alknet-flowgraph contents + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/architecture/adr-028-auth-irpc-service.md b/tasks/architecture/adr-028-auth-irpc-service.md new file mode 100644 index 0000000..23b2c6a --- /dev/null +++ b/tasks/architecture/adr-028-auth-irpc-service.md @@ -0,0 +1,49 @@ +--- +id: architecture/adr-028-auth-irpc-service +name: Write ADR-028 — Auth as irpc service +status: pending +depends_on: + - architecture/adr-029-identity-core-type +scope: narrow +risk: medium +impact: phase +level: implementation +--- + +## Description + +Write ADR-028 establishing that auth verification is provided via an irpc service protocol, with the `IdentityProvider` trait as the interface contract and `ConfigIdentityProvider` (ArcSwap-backed) as the default implementation. + +This ADR defines the relationship between the trait-based path and the irpc path: + +1. `IdentityProvider` trait in `alknet_core::auth` — the contract that callers depend on +2. `ConfigIdentityProvider` — default impl, reads from `ArcSwap`, no database needed +3. `AuthProtocol` irpc service enum — `VerifyPubkey`, `VerifyToken`, `ReloadKeys`, `CheckAccess` — behind `irpc` feature flag +4. Future: `StorageIdentityProvider` (in alknet-storage) backed by SQLite — additive, not replacing the trait + +The critical design point: callers go through `IdentityProvider`. The irpc service is one way to satisfy the trait. Feature-gating (`irpc` feature) means nodes that only do SSH tunneling don't need the service layer overhead. Both paths produce the same result — an `Identity` or rejection. + +## Acceptance Criteria + +- [ ] `docs/architecture/decisions/028-auth-irpc-service.md` exists +- [ ] ADR follows established format +- [ ] Context explains why a service layer is needed: for head nodes serving many users, in-memory key lookup doesn't scale; irpc provides async boundary for database-backed auth +- [ ] Decision states: IdentityProvider trait is the contract; ConfigIdentityProvider is the default; AuthProtocol irpc service is behind feature flag; irpc path and trait path produce identical Identity results; StorageIdentityProvider in alknet-storage is a future additive impl +- [ ] Shows AuthProtocol enum (`VerifyPubkey`, `VerifyToken`, `ReloadKeys`, `CheckAccess`) and AuthResult type +- [ ] Consequences: minimal deployments use ArcSwap without irpc; production deployments wire SQLite-backed service; feature flag keeps core lean +- [ ] References: research/services.md AuthProtocol, auth.md, research/configuration.md auth service approach, ADR-029 + +## References + +- docs/research/services.md — AuthProtocol definition +- docs/architecture/auth.md — IdentityProvider trait, Identity struct +- docs/research/configuration.md — auth service approach +- docs/research/integration-plan.md — ADR 028 entry, Phase 1.4 + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/architecture/adr-029-identity-core-type.md b/tasks/architecture/adr-029-identity-core-type.md new file mode 100644 index 0000000..560101b --- /dev/null +++ b/tasks/architecture/adr-029-identity-core-type.md @@ -0,0 +1,43 @@ +--- +id: architecture/adr-029-identity-core-type +name: Write ADR-029 — Identity as core type +status: pending +depends_on: [] +scope: single +risk: low +impact: project +level: implementation +--- + +## Description + +Write ADR-029 establishing `Identity` struct and `IdentityProvider` trait as core types in `alknet-core`. + +The `Identity` struct and `IdentityProvider` trait are already defined in `auth.md` (the draft architecture spec). This ADR formalizes the decision that they live in `alknet-core` — not in alknet-storage, not in alknet-services — so that core auth, forwarding policy, and call protocol all reference the same type without circular dependencies. + +The key constraint: alknet-core defines the trait, external crates provide implementations. `ConfigIdentityProvider` (ArcSwap-backed, in core) is the default. `StorageIdentityProvider` (SQLite-backed, in alknet-storage) is the production impl. Core never depends on storage. + +## Acceptance Criteria + +- [ ] `docs/architecture/decisions/029-identity-core-type.md` exists +- [ ] ADR follows established format +- [ ] Context explains why Identity must be in core: auth, forwarding, call protocol all need it; can't have circular deps +- [ ] Decision states: `Identity { id, scopes, resources }` and `IdentityProvider` trait live in `alknet_core::auth`; `id` is a fingerprint (config-based auth) or account UUID (database-backed auth); derivation and storage are external concerns; default `ConfigIdentityProvider` reads from `DynamicConfig.auth`; production `StorageIdentityProvider` is in alknet-storage +- [ ] Consequences: alknet-core has no database dependency; alknet-storage implements the core trait; the `id` field serves dual purpose (fingerprint or UUID) +- [ ] Resolves OQ-18: IdentityProvider owns scopes, ForwardingPolicy uses scopes from Identity +- [ ] References: auth.md, research/services.md Identity section, research/integration-plan.md + +## References + +- docs/architecture/auth.md — Identity and IdentityProvider trait definitions +- docs/research/services.md — Identity section +- docs/research/integration-plan.md — ADR 029 entry, Phase 1.2 +- docs/architecture/open-questions.md — OQ-18 + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/architecture/adr-030-static-dynamic-config-split.md b/tasks/architecture/adr-030-static-dynamic-config-split.md new file mode 100644 index 0000000..15c7767 --- /dev/null +++ b/tasks/architecture/adr-030-static-dynamic-config-split.md @@ -0,0 +1,49 @@ +--- +id: architecture/adr-030-static-dynamic-config-split +name: Write ADR-030 — Static/dynamic config split +status: pending +depends_on: [] +scope: narrow +risk: low +impact: phase +level: implementation +--- + +## Description + +Write ADR-030 establishing the split between `StaticConfig` (immutable after startup) and `DynamicConfig` (hot-reloadable at runtime) in alknet-core. + +This is largely a promotion from the well-analyzed research in `docs/research/configuration.md`. The ADR records why this split matters, what goes in each config, and how reload works. + +Key points: +- StaticConfig: transport mode, listen addr, TLS config, iroh config, host key, stealth mode, max auth attempts, max connections per IP — everything that requires socket/TLS renegotation to change +- DynamicConfig: auth policy (authorized keys, cert authorities), forwarding policy, rate limits — everything checked per-connection or per-channel +- ArcSwap for lock-free hot reload of DynamicConfig +- ServeOptions builder pattern is preserved; StaticConfig is constructed from ServeOptions +- TOML config file is an optional convenience input format (amends ADR-011, doesn't replace programmatic API) +- ConfigReloadHandle with `reload(DynamicConfig)` method +- NAPI exposes `reloadAuth()`, `reloadForwarding()`, `reloadAll()` on AlknetServer + +## Acceptance Criteria + +- [ ] `docs/architecture/decisions/030-static-dynamic-config-split.md` exists +- [ ] ADR follows established format +- [ ] Context explains the three failures: no hot reload of auth, no forwarding policy, no structured config beyond CLI flags +- [ ] Decision states: StaticConfig vs DynamicConfig split; ArcSwap for DynamicConfig; ServeOptions preserved as builder; TOML as optional convenience; ConfigService wraps reloads; amends ADR-011 +- [ ] Lists what's in StaticConfig and what's in DynamicConfig +- [ ] Consequences: auth and forwarding can be reloaded without restart; config file users get TOML format; programmatic-first API preserved +- [ ] References: research/configuration.md, ADR-011 + +## References + +- docs/research/configuration.md — full analysis, nearly spec-ready +- docs/architecture/decisions/011-no-ssh-config-programmatic-api.md — programmatic-first decision (amended, not superseded) +- docs/research/integration-plan.md — ADR 030 entry, Phase 1.1 + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/architecture/adr-031-forwarding-policy.md b/tasks/architecture/adr-031-forwarding-policy.md new file mode 100644 index 0000000..b1c2b1e --- /dev/null +++ b/tasks/architecture/adr-031-forwarding-policy.md @@ -0,0 +1,51 @@ +--- +id: architecture/adr-031-forwarding-policy +name: Write ADR-031 — Forwarding policy +status: pending +depends_on: [] +scope: narrow +risk: low +impact: phase +level: implementation +--- + +## Description + +Write ADR-031 establishing the forwarding policy model for `channel_open_direct_tcpip` access control. + +Currently any authenticated client can open a channel to any destination. This ADR defines `ForwardingPolicy`, `ForwardingRule`, and `TargetPattern` as part of `DynamicConfig` (reloadable without restart). + +Key design decisions from the research: +- Default-allow for migration compatibility (preserves current behavior) +- Default-deny is recommended for production +- Rules are evaluated per-channel-open, matched against the authenticated `Identity` from `IdentityProvider` +- `TransportKind` match in rules enables transport-specific restrictions (e.g., WebTransport clients restricted to alknet-* channels) +- OQ-12 resolved: start with global rules + principal matching from Identity.scopes; per-user scope from peer_credentials.metadata.scopes via IdentityProvider +- OQ-16 resolved: add TransportKind match in ForwardingRule; WebTransport clients can be scoped +- OQ-18 resolved: IdentityProvider owns scopes, ForwardingPolicy consumes them + +## Acceptance Criteria + +- [ ] `docs/architecture/decisions/031-forwarding-policy.md` exists +- [ ] ADR follows established format +- [ ] Context explains the security gap: any authenticated client gets unrestricted access +- [ ] Decision states: ForwardingPolicy with allow/deny rules, TargetPattern matching, default-allow for migration, TransportKind-aware rules, ForwardingPolicy is part of DynamicConfig (reloadable), Identity.scopes consumed by policy +- [ ] Includes ForwardingRule and TargetPattern type signatures +- [ ] Consequences: operators can restrict access per identity, per destination, per transport; default-allow preserves backward compatibility +- [ ] Resolves OQ-12, OQ-16, OQ-18 (reference in ADR) +- [ ] References: research/configuration.md, auth.md, open-questions.md + +## References + +- docs/research/configuration.md — ForwardingPolicy section +- docs/architecture/auth.md — Identity.scopes and IdentityProvider +- docs/architecture/open-questions.md — OQ-12, OQ-16, OQ-18 +- docs/research/integration-plan.md — ADR 031 entry, Phase 1.3 + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/architecture/adr-032-event-boundary-discipline.md b/tasks/architecture/adr-032-event-boundary-discipline.md new file mode 100644 index 0000000..a1514f8 --- /dev/null +++ b/tasks/architecture/adr-032-event-boundary-discipline.md @@ -0,0 +1,45 @@ +--- +id: architecture/adr-032-event-boundary-discipline +name: Write ADR-032 — Event boundary discipline +status: pending +depends_on: [] +scope: single +risk: low +impact: project +level: implementation +--- + +## Description + +Write ADR-032 establishing event boundary discipline as a hard architectural constraint. + +The research (services.md, storage.md) identifies three distinct communication patterns with clear boundaries: + +1. **Domain events** (Honker streams) — internal to the owning service, for state reconstruction. Never cross service boundaries without projection. +2. **irpc service calls** — synchronous request-response, within a node or cluster. Internal to the system. +3. **Call protocol events** (EventEnvelope) — cross-node, cross-language integration events. These are what cross boundaries. + +The ADR must state this as a hard constraint, not a suggestion. Conflating these three patterns is an anti-pattern that leads to leaky event stores and coupling. + +## Acceptance Criteria + +- [ ] `docs/architecture/decisions/032-event-boundary-discipline.md` exists +- [ ] ADR follows established format (Status, Context, Decision, Consequences, References) +- [ ] Context explains the three patterns and why conflating them is harmful +- [ ] Decision states: domain events stay within the owning service; irpc calls are synchronous internal boundaries; call protocol events are the only events that cross node boundaries; projection from domain events to integration events is required when crossing boundaries +- [ ] Consequences include: prevents leaky event stores, services are independently deployable, Honker and irpc are implementation details not exposed across boundaries +- [ ] References: research/services.md, research/storage.md, integration-plan.md + +## References + +- docs/research/services.md — event boundary discipline section +- docs/research/storage.md — Honker integration, event boundaries +- docs/research/integration-plan.md — ADR 032 entry + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/architecture/adr-033-operationenv-irpc-call-protocol.md b/tasks/architecture/adr-033-operationenv-irpc-call-protocol.md new file mode 100644 index 0000000..ad369fc --- /dev/null +++ b/tasks/architecture/adr-033-operationenv-irpc-call-protocol.md @@ -0,0 +1,62 @@ +--- +id: architecture/adr-033-operationenv-irpc-call-protocol +name: Write ADR-033 — OperationEnv, irpc, and call protocol relationship +status: pending +depends_on: + - architecture/adr-028-auth-irpc-service + - architecture/adr-027-crate-decomposition +scope: moderate +risk: high +impact: project +level: implementation +--- + +## Description + +Write ADR-033 establishing OperationEnv as the universal composition mechanism that unifies irpc services and call protocol operations from the handler's perspective. + +This is the most conceptually complex ADR. It must clearly establish: + +1. **OperationEnv is not an implementation detail from @alkdev/operations** — it's the universal composition mechanism. Handlers compose through `context.env[namespace][op](input)` regardless of dispatch path. + +2. **Three dispatch paths**, all producing the same result: + - **Local dispatch**: Direct function call through the operation registry. Zero serialization. + - **Service dispatch (irpc)**: In-cluster, Rust-to-Rust. Postcard serialization over tokio channels (local) or QUIC streams (remote). Domain-level. + - **Remote dispatch (call protocol)**: Cross-node, cross-language. JSON EventEnvelope over any (Transport, Interface) pair. Integration-level. + +3. **irpc is one dispatch backend for OperationEnv**, not a replacement for it. The call protocol is another dispatch backend. Both are Layer 3, at different scope boundaries. + +4. **The behavioral contract**: namespace + operation name → invoke with input, return output. The Rust implementation can use typed method dispatch or a registry internally, but the handler-facing API must preserve this contract. + +5. **An irpc service CAN be exposed as a call protocol operation** — the registry maps the path to a handler that internally calls the irpc service. + +This ADR resolves the potential confusion where "service" could mean irpc service protocol, call protocol operation, or external service. The consistent naming is: irpc service (in-cluster, Rust-to-Rust, postcard), operation (path-based, call protocol, cross-node, JSON), external service (any reachable endpoint). OperationEnv unifies them. + +## Acceptance Criteria + +- [ ] `docs/architecture/decisions/033-operationenv-irpc-call-protocol.md` exists +- [ ] ADR follows established format +- [ ] Context explains the confusion: irpc service vs call protocol operation vs external service are different dispatch mechanisms that need unification +- [ ] Decision states: OperationEnv is the universal composition mechanism; three dispatch paths (local, irpc, remote) all produce ResponseEnvelope; handlers don't know the dispatch path; irpc is one backend, not a replacement; an irpc service can back a call protocol operation +- [ ] Shows the dispatch diagram: OperationEnv → local | irpc service | remote call protocol +- [ ] Shows the composition layers: Call Protocol (Layer 3, external, JSON) → irpc Service (Layer 3, internal, postcard) → Honker Streams (domain events) +- [ ] Shows OperationEnv wiring example for minimal and production deployments +- [ ] Defines the consistent naming: irpc service / operation / external service +- [ ] Consequences: handlers compose through a single interface regardless of deployment; adapters (MCP, HTTP, DNS) map to operations through this interface; irpc gives type-safe efficient in-cluster calls; call protocol gives universal cross-language cross-node calls +- [ ] Hard constraint explicitly stated: the OperationEnv composition model must match the behavioral contract from @alkdev/operations +- [ ] References: research/services.md, @alkdev/operations, integration-plan.md + +## References + +- docs/research/services.md — OperationContext, OperationEnv, irpc service layer +- docs/research/integration-plan.md — ADR 033 entry, the three-layer clarification, OperationEnv section +- docs/architecture/call-protocol.md — OperationSpec, OperationRegistry, call protocol events +- @alkdev/operations — TypeScript OperationEnv implementation + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/architecture/adr-034-head-worker-terminology.md b/tasks/architecture/adr-034-head-worker-terminology.md new file mode 100644 index 0000000..b40d8f4 --- /dev/null +++ b/tasks/architecture/adr-034-head-worker-terminology.md @@ -0,0 +1,41 @@ +--- +id: architecture/adr-034-head-worker-terminology +name: Write ADR-034 — Head/worker terminology +status: pending +depends_on: [] +scope: single +risk: trivial +impact: project +level: implementation +--- + +## Description + +Write ADR-034 formalizing the decision to use head/worker terminology instead of hub/spoke throughout the project. + +This decision has already been applied in practice — `call-protocol.md`, `auth.md`, `open-questions.md`, and `napi-and-pubsub.md` were all updated to head/worker. The existing ADRs (024, 025) retain their original hub/spoke language because ADRs are historical records. ADR-018 is noted as superseded/extended by ADR-024 and the three-layer model. + +The ADR exists to formally record the decision so future contributors understand why and can reference it. + +## Acceptance Criteria + +- [ ] `docs/architecture/decisions/034-head-worker-terminology.md` exists +- [ ] ADR follows the established format (Status, Context, Decision, Consequences, References) +- [ ] Context explains why hub/spoke is being replaced (mesh topologies, a head is also a worker) +- [ ] Decision states: head/worker everywhere in new specs and code; ADRs retain original language as historical records +- [ ] Consequences note: natural mesh formation, consistency with integration plan terminology +- [ ] References: integration-plan.md, ADR-024, ADR-025 + +## References + +- docs/research/integration-plan.md — Phase 0 ADR 034 entry, inconsistencies section item 1 +- docs/architecture/decisions/024-bidirectional-call-protocol.md — uses hub/spoke historically +- docs/architecture/decisions/025-handler-spec-separation.md — uses hub/spoke historically + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/architecture/review-adr-foundation.md b/tasks/architecture/review-adr-foundation.md new file mode 100644 index 0000000..789c729 --- /dev/null +++ b/tasks/architecture/review-adr-foundation.md @@ -0,0 +1,51 @@ +--- +id: architecture/review-adr-foundation +name: Review Phase 0a ADRs — foundation decisions before spec writing +status: pending +depends_on: + - architecture/adr-034-head-worker-terminology + - architecture/adr-032-event-boundary-discipline + - architecture/adr-029-identity-core-type + - architecture/adr-030-static-dynamic-config-split + - architecture/adr-031-forwarding-policy + - architecture/adr-028-auth-irpc-service + - architecture/adr-027-crate-decomposition + - architecture/adr-026-transport-interface-separation + - architecture/adr-033-operationenv-irpc-call-protocol +scope: broad +risk: low +impact: project +level: review +--- + +## Description + +Review all Phase 0a ADRs (026-034) before proceeding to spec writing (Phase 0b). This is the critical checkpoint where we validate that the architectural decisions are consistent and complete before downstream specs reference them. + +This review should happen before any spec documents are created or updated, since specs will reference ADR numbers. + +## Acceptance Criteria + +- [ ] All 9 ADRs (026-034) are written and follow the established format +- [ ] ADRs cross-reference each other correctly (e.g., ADR-028 references ADR-029, ADR-027 references ADR-029) +- [ ] No ADR contradicts another (e.g., ADR-026's Interface trait must be compatible with ADR-033's OperationEnv) +- [ ] Crate dependency graph from ADR-027 is acyclic (core depends on nothing heavy) +- [ ] Layer boundaries from ADR-026 cleanly separate Transport, Interface, and Protocol +- [ ] OperationEnv dispatch model from ADR-033 is consistent with ADR-028 (auth service) and ADR-027 (crate decomposition) +- [ ] Terminology is consistent (head/worker everywhere per ADR-034) +- [ ] Open questions referenced in ADRs have proposed resolutions consistent with the decision +- [ ] Each ADR has clear consequences (both positive and negative) +- [ ] ADRs are added to the README.md ADR table + +## References + +- docs/architecture/decisions/ — all existing ADRs 001-025 for format reference +- docs/research/integration-plan.md — Phase 0 review checklist + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/auth/client-auth-handler.md b/tasks/auth/client-auth-handler.md index 1ad39ac..163c629 100644 --- a/tasks/auth/client-auth-handler.md +++ b/tasks/auth/client-auth-handler.md @@ -1,7 +1,7 @@ --- id: auth/client-auth-handler name: Implement client-side SSH authentication with Ed25519 key pairs -status: pending +status: completed depends_on: - auth/key-loading - auth/error-types diff --git a/tasks/auth/error-types.md b/tasks/auth/error-types.md index 7a379c3..e41811f 100644 --- a/tasks/auth/error-types.md +++ b/tasks/auth/error-types.md @@ -1,7 +1,7 @@ --- id: auth/error-types name: Define error types for transport, auth, channel, and configuration layers -status: pending +status: completed depends_on: - setup/project-init scope: narrow diff --git a/tasks/auth/key-loading.md b/tasks/auth/key-loading.md index 4fd7d95..5b28aea 100644 --- a/tasks/auth/key-loading.md +++ b/tasks/auth/key-loading.md @@ -1,7 +1,7 @@ --- id: auth/key-loading name: Implement SSH key material loading (file paths and in-memory data) -status: pending +status: completed depends_on: - auth/error-types - setup/project-init diff --git a/tasks/auth/server-auth-handler.md b/tasks/auth/server-auth-handler.md index 93c7e7d..9350b8a 100644 --- a/tasks/auth/server-auth-handler.md +++ b/tasks/auth/server-auth-handler.md @@ -1,7 +1,7 @@ --- id: auth/server-auth-handler name: Implement server-side authentication (Ed25519 keys + OpenSSH cert-authority) -status: pending +status: completed depends_on: - auth/key-loading - auth/error-types diff --git a/tasks/cli/connect-command.md b/tasks/cli/connect-command.md index fc69f24..04e01c9 100644 --- a/tasks/cli/connect-command.md +++ b/tasks/cli/connect-command.md @@ -1,7 +1,7 @@ --- id: cli/connect-command name: Implement `alknet connect` CLI subcommand with clap -status: pending +status: completed depends_on: - client/connect-options scope: moderate diff --git a/tasks/client/channel-manager.md b/tasks/client/channel-manager.md index fd268a5..3145a39 100644 --- a/tasks/client/channel-manager.md +++ b/tasks/client/channel-manager.md @@ -1,7 +1,7 @@ --- id: client/channel-manager name: Implement ChannelManager — SSH session management, channel opens, reconnection -status: done +status: completed depends_on: - auth/client-auth-handler - transport/trait-and-types diff --git a/tasks/client/connect-options.md b/tasks/client/connect-options.md index ec8e183..4c701dc 100644 --- a/tasks/client/connect-options.md +++ b/tasks/client/connect-options.md @@ -1,7 +1,7 @@ --- id: client/connect-options name: Implement ConnectOptions struct and client session orchestration with graceful shutdown -status: pending +status: completed depends_on: - client/channel-manager - client/socks5-server diff --git a/tasks/client/port-forwarding.md b/tasks/client/port-forwarding.md index 99df1e3..6ca1e61 100644 --- a/tasks/client/port-forwarding.md +++ b/tasks/client/port-forwarding.md @@ -1,7 +1,7 @@ --- id: client/port-forwarding name: Implement port forwarding — local (-L) and remote (-R) forwards -status: pending +status: completed depends_on: - auth/client-auth-handler - transport/trait-and-types diff --git a/tasks/client/socks5-server.md b/tasks/client/socks5-server.md index 755e94e..e915ae3 100644 --- a/tasks/client/socks5-server.md +++ b/tasks/client/socks5-server.md @@ -1,7 +1,7 @@ --- id: client/socks5-server name: Implement SOCKS5 server — local proxy that forwards through SSH channels -status: pending +status: completed depends_on: - auth/client-auth-handler - transport/trait-and-types diff --git a/tasks/meta/auth-layer.md b/tasks/meta/auth-layer.md index 8b174fe..e6b049b 100644 --- a/tasks/meta/auth-layer.md +++ b/tasks/meta/auth-layer.md @@ -1,7 +1,7 @@ --- id: meta/auth-layer name: Complete auth layer — error types, key loading, server auth, client auth -status: pending +status: completed depends_on: - auth/error-types - auth/key-loading diff --git a/tasks/meta/client-layer.md b/tasks/meta/client-layer.md index 693f0eb..62e124a 100644 --- a/tasks/meta/client-layer.md +++ b/tasks/meta/client-layer.md @@ -1,7 +1,7 @@ --- id: meta/client-layer name: Complete client layer — SOCKS5, port forwarding, channel manager, ConnectOptions -status: pending +status: completed depends_on: - client/socks5-server - client/port-forwarding diff --git a/tasks/meta/transport-layer.md b/tasks/meta/transport-layer.md index 232c760..e3b605a 100644 --- a/tasks/meta/transport-layer.md +++ b/tasks/meta/transport-layer.md @@ -1,7 +1,7 @@ --- id: meta/transport-layer name: Complete transport layer — trait, TCP, TLS, iroh, ACME -status: pending +status: completed depends_on: - transport/trait-and-types - transport/tcp-transport diff --git a/tasks/napi/connect-function.md b/tasks/napi/connect-function.md index c054f9c..f112eab 100644 --- a/tasks/napi/connect-function.md +++ b/tasks/napi/connect-function.md @@ -1,7 +1,7 @@ --- id: napi/connect-function name: Implement NAPI connect() — single SSH channel as Duplex stream -status: pending +status: completed depends_on: - napi/project-setup - client/channel-manager diff --git a/tasks/napi/project-setup.md b/tasks/napi/project-setup.md index 6e52ac2..ccb0c74 100644 --- a/tasks/napi/project-setup.md +++ b/tasks/napi/project-setup.md @@ -1,7 +1,7 @@ --- id: napi/project-setup name: Set up alknet-napi project with napi-rs build tooling and TypeScript types -status: pending +status: completed depends_on: - setup/project-init scope: moderate diff --git a/tasks/review/core-foundation.md b/tasks/review/core-foundation.md index 7efaed5..808d28a 100644 --- a/tasks/review/core-foundation.md +++ b/tasks/review/core-foundation.md @@ -1,7 +1,7 @@ --- id: review/core-foundation name: Review core foundation — transport traits, auth, error types, key loading -status: pending +status: completed depends_on: - meta/transport-layer - meta/auth-layer diff --git a/tasks/server/channel-proxy.md b/tasks/server/channel-proxy.md index f0ef27c..6ae7763 100644 --- a/tasks/server/channel-proxy.md +++ b/tasks/server/channel-proxy.md @@ -1,7 +1,7 @@ --- id: server/channel-proxy name: Implement server channel proxy — direct TCP and outbound proxy connections -status: pending +status: completed depends_on: - server/handler - auth/error-types diff --git a/tasks/server/control-channel.md b/tasks/server/control-channel.md index cbec830..73f185c 100644 --- a/tasks/server/control-channel.md +++ b/tasks/server/control-channel.md @@ -1,7 +1,7 @@ --- id: server/control-channel name: Implement alknet-control reserved channel for pubsub event bus bridging (ADR-018) -status: pending +status: completed depends_on: - server/handler - auth/error-types diff --git a/tasks/server/handler.md b/tasks/server/handler.md index e03314f..92489ec 100644 --- a/tasks/server/handler.md +++ b/tasks/server/handler.md @@ -1,7 +1,7 @@ --- id: server/handler name: Implement ServerHandler — russh server handler with auth and channel dispatch -status: pending +status: completed depends_on: - auth/server-auth-handler - transport/trait-and-types diff --git a/tasks/server/rate-limiting-and-logging.md b/tasks/server/rate-limiting-and-logging.md index 0407710..619361a 100644 --- a/tasks/server/rate-limiting-and-logging.md +++ b/tasks/server/rate-limiting-and-logging.md @@ -1,7 +1,7 @@ --- id: server/rate-limiting-and-logging name: Implement server rate limiting and fail2ban-friendly structured logging -status: pending +status: completed depends_on: - server/handler scope: narrow diff --git a/tasks/server/stealth-mode.md b/tasks/server/stealth-mode.md index fe922e0..be844b6 100644 --- a/tasks/server/stealth-mode.md +++ b/tasks/server/stealth-mode.md @@ -1,7 +1,7 @@ --- id: server/stealth-mode name: Implement stealth mode — protocol multiplexing on port 443 (ADR-017) -status: pending +status: completed depends_on: - transport/tls-transport - server/handler diff --git a/tasks/setup/project-init.md b/tasks/setup/project-init.md index e6fc895..b0b90d8 100644 --- a/tasks/setup/project-init.md +++ b/tasks/setup/project-init.md @@ -1,7 +1,7 @@ --- id: setup/project-init name: Initialize Cargo workspace with alknet, alknet-core, and alknet-napi crates -status: pending +status: completed depends_on: [] scope: moderate risk: low diff --git a/tasks/setup/test-infrastructure.md b/tasks/setup/test-infrastructure.md index f2061fb..04abb52 100644 --- a/tasks/setup/test-infrastructure.md +++ b/tasks/setup/test-infrastructure.md @@ -1,7 +1,7 @@ --- id: setup/test-infrastructure name: Set up test infrastructure with tokio test helpers and integration test skeleton -status: pending +status: completed depends_on: - setup/project-init scope: narrow diff --git a/tasks/transport/acme-cert-provisioning.md b/tasks/transport/acme-cert-provisioning.md index 9c076c2..f4b1a6e 100644 --- a/tasks/transport/acme-cert-provisioning.md +++ b/tasks/transport/acme-cert-provisioning.md @@ -1,7 +1,7 @@ --- id: transport/acme-cert-provisioning name: Implement ACME Lets Encrypt certificate provisioning (feature-gated acme) -status: pending +status: completed depends_on: - transport/tls-transport scope: moderate diff --git a/tasks/transport/iroh-transport.md b/tasks/transport/iroh-transport.md index ca630af..2f28783 100644 --- a/tasks/transport/iroh-transport.md +++ b/tasks/transport/iroh-transport.md @@ -1,7 +1,7 @@ --- id: transport/iroh-transport name: Implement IrohTransport and IrohAcceptor (feature-gated iroh) -status: pending +status: completed depends_on: - transport/trait-and-types - transport/tcp-transport diff --git a/tasks/transport/tcp-transport.md b/tasks/transport/tcp-transport.md index 25ccae0..5230634 100644 --- a/tasks/transport/tcp-transport.md +++ b/tasks/transport/tcp-transport.md @@ -1,7 +1,7 @@ --- id: transport/tcp-transport name: Implement TcpTransport and TcpAcceptor -status: pending +status: completed depends_on: - transport/trait-and-types scope: narrow diff --git a/tasks/transport/tls-transport.md b/tasks/transport/tls-transport.md index 1b9fa1d..c6493bc 100644 --- a/tasks/transport/tls-transport.md +++ b/tasks/transport/tls-transport.md @@ -1,7 +1,7 @@ --- id: transport/tls-transport name: Implement TlsTransport and TlsAcceptor (feature-gated tls) -status: pending +status: completed depends_on: - transport/tcp-transport - transport/trait-and-types diff --git a/tasks/transport/trait-and-types.md b/tasks/transport/trait-and-types.md index cafa9cd..c9caa21 100644 --- a/tasks/transport/trait-and-types.md +++ b/tasks/transport/trait-and-types.md @@ -1,7 +1,7 @@ --- id: transport/trait-and-types name: Define Transport trait, TransportAcceptor trait, TransportInfo, and TransportKind types -status: pending +status: completed depends_on: - setup/project-init scope: narrow