tasks: decompose Phase 0a ADR foundation and mark prior tasks completed
Add 10 new tasks under tasks/architecture/ for Phase 0a (ADR writing): - 9 ADR tasks (026-034) with dependency-ordered structure - 1 review checkpoint task before Phase 0b spec writing ADR dependency graph (3 generations): Gen 1 (parallel): 026, 029, 030, 031, 032, 034 Gen 2 (depends on 029): 027, 028 Gen 3 (depends on 027+028): 033 Gen 4: review checkpoint Also mark all 34 prior implementation tasks as completed — they were finished but still showing as pending in the taskgraph.
This commit is contained in:
63
tasks/architecture/adr-026-transport-interface-separation.md
Normal file
63
tasks/architecture/adr-026-transport-interface-separation.md
Normal file
@@ -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
|
||||
57
tasks/architecture/adr-027-crate-decomposition.md
Normal file
57
tasks/architecture/adr-027-crate-decomposition.md
Normal file
@@ -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<N,E> 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
|
||||
49
tasks/architecture/adr-028-auth-irpc-service.md
Normal file
49
tasks/architecture/adr-028-auth-irpc-service.md
Normal file
@@ -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<DynamicConfig>`, 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
|
||||
43
tasks/architecture/adr-029-identity-core-type.md
Normal file
43
tasks/architecture/adr-029-identity-core-type.md
Normal file
@@ -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
|
||||
49
tasks/architecture/adr-030-static-dynamic-config-split.md
Normal file
49
tasks/architecture/adr-030-static-dynamic-config-split.md
Normal file
@@ -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
|
||||
51
tasks/architecture/adr-031-forwarding-policy.md
Normal file
51
tasks/architecture/adr-031-forwarding-policy.md
Normal file
@@ -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
|
||||
45
tasks/architecture/adr-032-event-boundary-discipline.md
Normal file
45
tasks/architecture/adr-032-event-boundary-discipline.md
Normal file
@@ -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
|
||||
@@ -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
|
||||
41
tasks/architecture/adr-034-head-worker-terminology.md
Normal file
41
tasks/architecture/adr-034-head-worker-terminology.md
Normal file
@@ -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
|
||||
51
tasks/architecture/review-adr-foundation.md
Normal file
51
tasks/architecture/review-adr-foundation.md
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user