docs: replace alkvault scaffold with alkcall project conventions
- AGENTS.md: full rewrite for the call+channels RPC crate (async/tokio, vendored core types, alktype dep, producer/consumer framing, the two stable wire formats, no-env-vars invariant, OperationEnv trait, abort cascade, AccessControl peer auth, ADR index for both halves) - implementation-specialist.md: replace vault crypto conventions (OsRng, zeroize, AES-GCM) with 15 alkcall protocol conventions matching AGENTS.md - docs/sdd_process.md: fix alkvault -> alkcall reference Verification: no code changed (docs-only) commit 0a031cd..HEAD
This commit is contained in:
@@ -209,28 +209,56 @@ This is especially important for complex tasks that span many file operations.
|
|||||||
|
|
||||||
Read `AGENTS.md` at project root for full details. Key rules:
|
Read `AGENTS.md` at project root for full details. Key rules:
|
||||||
|
|
||||||
1. **No comments in code** — Per project convention.
|
1. **No comments in code** — Per project convention. Doc comments (`///`, `//!`)
|
||||||
2. **Error handling** — Use `anyhow::Result` for application code, `thiserror` for
|
are fine and expected on public API.
|
||||||
library error types. Never panic in library code.
|
2. **Error handling** — `thiserror` for library error types. No panics in
|
||||||
3. **No `unwrap()` or `expect()` outside tests** — These are debug signals that
|
library code. No `unwrap()` or `expect()` outside tests. For poisoned
|
||||||
something wasn't clear. If you reach for `unwrap()`, it means the error
|
`RwLock`/`Mutex`, use `unwrap_or_else(|e| e.into_inner())` so a panic in one
|
||||||
handling path wasn't specified — stop and think about what should actually
|
operation does not cascade to other operations.
|
||||||
happen on that error. For poisoned locks, use
|
3. **`tokio` is the async runtime** — all I/O is async. Use `tokio::sync`
|
||||||
`unwrap_or_else(|e| e.into_inner())` or explicit error propagation. A panic
|
primitives (`oneshot`, `mpsc`) for request correlation and subscription
|
||||||
in one operation must not cascade to other operations.
|
channels; `parking_lot` for short-held internal locks (`PendingRequestMap`).
|
||||||
4. **Cryptographic nonces use `OsRng`** — AES-GCM IVs and any other cryptographic
|
4. **No secret material on the wire** — `call.requested`/`call.responded`
|
||||||
nonces must use `OsRng` (or equivalent CSPRNG), never `rand::random()`. IV
|
payloads and `OperationContext.metadata` carry no private keys, API keys, or
|
||||||
reuse under the same key is catastrophic for GCM.
|
decrypted credentials. Outbound credentials flow through `Capabilities`
|
||||||
5. **Secret material is zeroized on drop** — Any type holding derived keys,
|
injected at the assembly layer → `HandlerRegistration.capabilities` →
|
||||||
decrypted credentials, or other secret material must derive `Zeroize` and
|
`OperationContext.capabilities` → handler.
|
||||||
`ZeroizeOnDrop`. Secrets must not linger in freed heap memory.
|
5. **No-env-vars invariant** — no handler reads outbound credentials from any
|
||||||
6. **Feature flags** — Transports are feature-gated (`tls`, `iroh`, `acme`). Base
|
source other than `OperationContext.capabilities`. This is a spec-level
|
||||||
crate should compile lean.
|
invariant, not a runtime convention.
|
||||||
7. **Async runtime** — `tokio` is the async runtime. All I/O is async.
|
6. **`OperationEnv` must remain a trait** — the trait-based design enables
|
||||||
8. **Naming conventions** — Rust standard: `snake_case` for functions/variables/
|
registry layering (session overlays, connection overlays, peer-keyed
|
||||||
modules, `PascalCase` for types/traits, `SCREAMING_SNAKE_CASE` for constants.
|
composition). Do not make it concrete or hardcode the global registry.
|
||||||
9. **Module structure** — One module per component under `src/`. Re-export via
|
7. **Wire formats are stable** — `EventEnvelope` (`{ type, id, payload }` +
|
||||||
`mod.rs` or `lib.rs` as appropriate.
|
length-prefixed JSON framing) and the channels 8-byte chunk header
|
||||||
|
(`[channel_id:u32 BE][length:u32 BE][payload]`) are one-way doors. New event
|
||||||
|
types may be added; existing shapes must not change.
|
||||||
|
8. **Producer/consumer, not server/client** — both sides of a call or channels
|
||||||
|
connection can initiate. Use "producer"/"consumer" or "accept side"/"connect
|
||||||
|
side," not "server"/"client."
|
||||||
|
9. **Vendored core types** — `Connection`, `ProtocolHandler`, `BiStream`,
|
||||||
|
`BidiStreamSource`, `AuthContext`, `IdentityProvider`, `Identity`,
|
||||||
|
`AuthToken`, `Capabilities`, `OwnershipProvider`, `HandlerError`,
|
||||||
|
`StreamError` live in this crate. Do not add a separate `alkcore` dependency.
|
||||||
|
Keep them lean (no TLS, no transport coupling, no endpoint/accept-loop).
|
||||||
|
10. **`alktype` dependency** — use `alktype` for binary layout (channels chunk
|
||||||
|
header, future binary payload schemas) and JSON payload schema validation
|
||||||
|
(`OperationSpec`'s `input_schema`/`output_schema`). Do not roll your own.
|
||||||
|
11. **Feature flags** — transports may be feature-gated if the need arises. The
|
||||||
|
base crate should compile lean (no `quinn`, no `iroh` unless the feature is
|
||||||
|
on). Verify both `cargo test` (default) and `cargo test --all-features` pass
|
||||||
|
if features are added.
|
||||||
|
12. **Abort cascades to descendants** — `call.aborted` for a parent cascades to
|
||||||
|
all non-terminal descendants. Default `abort-dependents`;
|
||||||
|
`continue-running` opt-in. The composing handler decides the child's policy,
|
||||||
|
not the wire caller.
|
||||||
|
13. **Peer authorization via `AccessControl`** — a remote peer's call is
|
||||||
|
authorized by `AccessControl::check(peer_identity)`. No `remote_safe` flag,
|
||||||
|
no `trusted_peer` bypass. `Visibility::Internal` ops are never wire-callable.
|
||||||
|
14. **Naming conventions** — Rust standard: `snake_case` for functions/variables/
|
||||||
|
modules, `PascalCase` for types/traits, `SCREAMING_SNAKE_CASE` for constants.
|
||||||
|
15. **Module structure** — one module per file under `src/`, re-exported from
|
||||||
|
`src/lib.rs`. Public API surface is `lib.rs` re-exports.
|
||||||
|
|
||||||
## Key Principles
|
## Key Principles
|
||||||
|
|
||||||
|
|||||||
263
AGENTS.md
263
AGENTS.md
@@ -15,8 +15,8 @@ explicitly asked."
|
|||||||
The workflow:
|
The workflow:
|
||||||
|
|
||||||
1. Make the change
|
1. Make the change
|
||||||
2. Verify: `cargo test --all-features`, `cargo clippy --all-features
|
2. Verify: `cargo test`, `cargo clippy --all-targets -- -D warnings`,
|
||||||
--all-targets`, `cargo doc --no-deps --all-features` if docs changed
|
`cargo fmt --check`, `cargo doc --no-deps` if docs changed
|
||||||
3. Inspect `git status` and `git diff` before staging — stage only the
|
3. Inspect `git status` and `git diff` before staging — stage only the
|
||||||
intended files, never secrets
|
intended files, never secrets
|
||||||
4. Write a concise commit message matching the repo style (see `git log
|
4. Write a concise commit message matching the repo style (see `git log
|
||||||
@@ -31,7 +31,9 @@ Exceptions — **do not** commit or push without asking:
|
|||||||
it kept)
|
it kept)
|
||||||
- The user is actively reviewing the diff and may ask for changes
|
- The user is actively reviewing the diff and may ask for changes
|
||||||
- The change touches published wire formats or semver-relevant public API
|
- The change touches published wire formats or semver-relevant public API
|
||||||
(this repo is on crates.io; `EncryptedData` is frozen per ADR-018)
|
(this crate will be on crates.io; the `EventEnvelope` shape and the
|
||||||
|
channels 8-byte chunk header are wire-format-stable — see ADR-064 and
|
||||||
|
ADR-071 in the alknet source docs, to be renumbered as alkcall ADRs)
|
||||||
- You'd be force-pushing, amending a published commit, creating an empty
|
- You'd be force-pushing, amending a published commit, creating an empty
|
||||||
commit, or skipping hooks
|
commit, or skipping hooks
|
||||||
|
|
||||||
@@ -42,85 +44,244 @@ failed one.
|
|||||||
Git identity is preconfigured (`glm-5.2 <glm-5.2@alk.dev>`). Do not
|
Git identity is preconfigured (`glm-5.2 <glm-5.2@alk.dev>`). Do not
|
||||||
change `git config`, skip hooks, or use `git commit -i`.
|
change `git config`, skip hooks, or use `git commit -i`.
|
||||||
|
|
||||||
## Project Conventions (Rust / cryptographic library)
|
## Project Conventions (Rust / RPC protocol crate)
|
||||||
|
|
||||||
This is a cryptographic vault crate. The conventions below apply to all
|
This is the call + channels RPC crate — the unification of
|
||||||
work in `src/` and `tests/`. They mirror `.opencode/agents/
|
`alknet-call` (structured JSON RPC: operations, streaming subscriptions,
|
||||||
implementation-specialist.md` §Project Conventions and are repeated here
|
service discovery) and `alknet-channels` (multiplexing proxy: N logical
|
||||||
so they apply to every session, not just spawned implementation agents.
|
channels over one transport stream, channel 0 pre-negotiated as
|
||||||
|
`alknet/call`). 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
|
1. **No comments in code** unless the user explicitly asks. This is a
|
||||||
project-wide convention. Doc comments (`///`, `//!`) are fine and
|
project-wide convention. Doc comments (`///`, `//!`) are fine and
|
||||||
expected on public API. Inline `//` comments only when the user asks
|
expected on public API. Inline `//` comments only when the user asks
|
||||||
or when a non-obvious safety/correctness constraint would otherwise be
|
or when a non-obvious safety/correctness constraint would otherwise be
|
||||||
missed (e.g., "fresh per call — IV reuse under the same key is
|
missed (e.g., "fresh per call — ID reuse under the same connection
|
||||||
catastrophic").
|
corrupts `PendingRequestMap` correlation and the abort-cascade
|
||||||
|
tree").
|
||||||
|
|
||||||
2. **Error handling** — `thiserror` for library error types, `anyhow` for
|
2. **Error handling** — `thiserror` for library error types. No panics
|
||||||
application code (this crate is a library; use `thiserror`). No panics
|
|
||||||
in library code. No `unwrap()` or `expect()` outside tests. If you
|
in library code. No `unwrap()` or `expect()` outside tests. If you
|
||||||
reach for `unwrap`, the error path wasn't specified — stop and decide
|
reach for `unwrap`, the error path wasn't specified — stop and decide
|
||||||
what should actually happen. For poisoned `RwLock`/`Mutex`, use
|
what should actually happen. For poisoned `RwLock`/`Mutex`, use
|
||||||
`unwrap_or_else(|e| e.into_inner())` so a panic in one operation does
|
`unwrap_or_else(|e| e.into_inner())` so a panic in one operation does
|
||||||
not cascade to other operations.
|
not cascade to other operations.
|
||||||
|
|
||||||
3. **Cryptographic nonces use `OsRng`** — AES-GCM IVs and any other
|
3. **`tokio` is the async runtime** — all I/O is async. The call
|
||||||
cryptographic nonces must use `SysRng`/`OsRng` (or equivalent CSPRNG),
|
protocol's stream handling, the channels demux/mux, `from_call`
|
||||||
never `rand::random()`. IV reuse under the same key is catastrophic
|
discovery, and the dispatch loop are all async. Do not introduce
|
||||||
for GCM (authenticity breaks, two-time-pad on plaintext). See
|
blocking I/O on the async path. Use `tokio::sync` primitives
|
||||||
`docs/architecture/encryption.md` §Security Constraints.
|
(`oneshot`, `mpsc`) for request correlation and subscription
|
||||||
|
channels; `parking_lot` for short-held internal locks
|
||||||
|
(`PendingRequestMap`).
|
||||||
|
|
||||||
4. **Secret material is zeroized on drop** — any type holding derived
|
4. **No secret material on the wire** — the call protocol carries no
|
||||||
keys, decrypted credentials, or other secret material must derive
|
private keys, API keys, mnemonics, or decrypted credentials in
|
||||||
`Zeroize` and `ZeroizeOnDrop`. Secrets must not linger in freed heap
|
`call.requested` payloads, `call.responded` payloads, or
|
||||||
memory. See `EncryptionKey` and `Seed` for the pattern.
|
`OperationContext.metadata`. Outbound credentials flow through
|
||||||
|
`Capabilities` injected at the assembly layer →
|
||||||
|
`HandlerRegistration.capabilities` → `OperationContext.capabilities`
|
||||||
|
→ handler. See the no-env-vars invariant below and ADR-014 (alknet
|
||||||
|
source).
|
||||||
|
|
||||||
5. **Feature flags** — `secp256k1` is a feature gate for the Ethereum
|
5. **No-env-vars invariant** — no handler reads outbound credentials
|
||||||
BIP-0032 derivation path. The base crate compiles lean (no networking,
|
from any source other than `OperationContext.capabilities`. The
|
||||||
no `tokio`, no `secp256k1` unless the feature is on). Verify both
|
credential injection path is vault → assembly layer → `Capabilities`
|
||||||
`cargo test` (default) and `cargo test --all-features` pass.
|
→ `HandlerRegistration.capabilities` → `OperationContext.capabilities`
|
||||||
|
→ handler. Downstream consumers' `std::env::var` reads are
|
||||||
|
unreachable because the assembly layer never calls `Default::default()`.
|
||||||
|
This is a spec-level invariant, not a runtime convention.
|
||||||
|
|
||||||
6. **No `async`** — this crate is synchronous (`std::sync::RwLock`,
|
6. **`OperationEnv` must remain a trait** — the trait-based design
|
||||||
direct method calls). No `tokio` dependency (ADR-025). Do not
|
enables registry layering (session overlays, connection overlays,
|
||||||
introduce `async`/`.await` or async-sync primitives.
|
peer-keyed composition). Making `OperationEnv` concrete or hardcoding
|
||||||
|
the global registry into the dispatch path would close the
|
||||||
|
session-overlay and connection-overlay patterns. This is the same
|
||||||
|
integration-point pattern as `IdentityProvider`. See ADR-024, ADR-029
|
||||||
|
(alknet source).
|
||||||
|
|
||||||
7. **Naming** — Rust standard: `snake_case` for functions/variables/
|
7. **Wire formats are stable** — two wire formats live in this crate:
|
||||||
modules, `PascalCase` for types/traits, `SCREAMING_SNAKE_CASE` for
|
- **`EventEnvelope`** (`{ type, id, payload }` with length-prefixed
|
||||||
constants.
|
JSON framing) — the call protocol's wire format. Cross-language
|
||||||
|
consumable (TypeScript, Python, any language). The envelope shape
|
||||||
|
and the five event types (`call.requested`, `call.responded`,
|
||||||
|
`call.completed`, `call.aborted`, `call.error`) are stable. New
|
||||||
|
event types may be added; existing ones must not change shape. See
|
||||||
|
ADR-064 (alknet source).
|
||||||
|
- **Channels 8-byte chunk header** (`[channel_id:u32 BE][length:u32
|
||||||
|
BE][payload]`) — the channels wire format. This is a one-way door:
|
||||||
|
changing the header format breaks all peers. The channels layer has
|
||||||
|
no `stream_type` concept — the handler owns its sub-stream
|
||||||
|
multiplexing on the `BiStream` it receives. See ADR-071, ADR-093
|
||||||
|
(alknet source).
|
||||||
|
|
||||||
8. **Module structure** — one module per file under `src/`, re-exported
|
8. **Producer/consumer, not server/client** — both sides of a call or
|
||||||
from `src/lib.rs`. Public API surface is `lib.rs` re-exports.
|
channels connection can initiate. A producer exposes operations
|
||||||
|
(call) or opens data channels (channels); a consumer calls operations
|
||||||
|
or opens channels. Both sides can be both simultaneously — connection
|
||||||
|
direction (who opened it) is independent of call/channel direction
|
||||||
|
(who calls/opens). Avoid "server" and "client" framing in docs and
|
||||||
|
API names; use "producer" and "consumer," or "accept side" / "connect
|
||||||
|
side" for the connection-establishment half specifically. See ADR-017,
|
||||||
|
ADR-073 §direction semantics (alknet source).
|
||||||
|
|
||||||
9. **Wire format is frozen** — `EncryptedData` is a stable wire format
|
9. **Vendored core types** — the types formerly in `alknet-core`
|
||||||
shared with `alknet-storage` and the TypeScript `@alkdev/storage`
|
(`Connection`, `ProtocolHandler`, `BiStream`, `BidiStreamSource`,
|
||||||
consumer by type-level agreement (ADR-018). Fields, encoding, and
|
`AuthContext`, `IdentityProvider`, `Identity`, `AuthToken`,
|
||||||
semantics are locked. No field may be removed or renamed; new fields
|
`Capabilities`, `OwnershipProvider`, `HandlerError`, `StreamError`)
|
||||||
must be optional (default on deserialization) and must not change the
|
live in this crate. They are the home for these types going forward —
|
||||||
meaning of existing fields. The `salt` field is unused in v2 key
|
do not add a separate `alkcore` dependency. When the alknet mono-repo
|
||||||
derivation (ADR-020) but retained for wire-format compatibility — do
|
is reworked, it will consume alkcall's versions. Keep these types
|
||||||
not remove it.
|
lean (no TLS, no transport coupling, no endpoint/accept-loop); the
|
||||||
|
dial and the TLS config are concerns of the consumer, not of this
|
||||||
|
crate. See ADR-065, ADR-070, ADR-092 (alknet source).
|
||||||
|
|
||||||
|
10. **`alktype` dependency** — use `alktype` for binary layout (the
|
||||||
|
channels chunk header, future binary payload schemas) and JSON
|
||||||
|
payload schema validation (`OperationSpec`'s `input_schema`/
|
||||||
|
`output_schema`). Do not roll your own offset map or validator. See
|
||||||
|
the alktype crate at `/workspace/@alkdev/alktype`.
|
||||||
|
|
||||||
|
11. **Feature flags** — transports may be feature-gated if the need
|
||||||
|
arises. The base crate should compile lean (no `quinn`, no `iroh`
|
||||||
|
unless the feature is on). The vendored `Connection` type supports
|
||||||
|
`Connection::from_stream` / `from_bidi` for transport-agnostic
|
||||||
|
construction — the call and channels protocols are
|
||||||
|
transport-agnostic by construction. Verify both `cargo test`
|
||||||
|
(default) and `cargo test --all-features` pass if features are
|
||||||
|
added.
|
||||||
|
|
||||||
|
12. **Naming** — Rust standard: `snake_case` for functions/variables/
|
||||||
|
modules, `PascalCase` for types/traits, `SCREAMING_SNAKE_CASE` for
|
||||||
|
constants.
|
||||||
|
|
||||||
|
13. **Module structure** — one module per file under `src/`, re-exported
|
||||||
|
from `src/lib.rs`. Public API surface is `lib.rs` re-exports. The
|
||||||
|
crate has two subsystems: `registry` (operation specs, context,
|
||||||
|
dispatch, registry) and `protocol` (wire format, streams, adapter,
|
||||||
|
dispatch loop, pending requests, abort cascade) for the call half;
|
||||||
|
and the channels half (wire format, `ChannelsAdapter`,
|
||||||
|
`ChannelManager`, `ChannelBidiStreamSource`, channel lifecycle
|
||||||
|
operations, `ChannelClient`).
|
||||||
|
|
||||||
|
14. **Abort cascades to descendants** — `call.aborted` for a parent
|
||||||
|
request cascades to all non-terminal descendants in the call tree.
|
||||||
|
Default policy is `abort-dependents`; `continue-running` is an
|
||||||
|
opt-in for long-running work. The abort policy is set on
|
||||||
|
`OperationContext` and propagated through `OperationEnv::invoke()`
|
||||||
|
— the composing handler decides the child's policy, not the wire
|
||||||
|
caller. See ADR-016 (alknet source).
|
||||||
|
|
||||||
|
15. **Peer authorization via `AccessControl`** — a remote peer's call is
|
||||||
|
authorized by `AccessControl::check(peer_identity)` against the op's
|
||||||
|
`AccessControl` — the same mechanism that gates every other call. No
|
||||||
|
`remote_safe` flag, no `trusted_peer` bypass. An op with
|
||||||
|
`AccessControl::default()` is callable by any peer; an op with
|
||||||
|
`required_scopes` is callable only by peers whose `Identity.scopes`
|
||||||
|
satisfy them; an op with `Visibility::Internal` is never callable
|
||||||
|
from the wire. See ADR-029 (alknet source).
|
||||||
|
|
||||||
## Verification Commands
|
## Verification Commands
|
||||||
|
|
||||||
Run these before committing. All must pass.
|
Run these before committing. All must pass.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo test --all-features # full suite (~108 tests)
|
cargo test # full suite
|
||||||
cargo test # default features (~101 tests)
|
cargo clippy --all-targets -- -D warnings
|
||||||
cargo clippy --all-features --all-targets
|
cargo fmt --check
|
||||||
cargo doc --no-deps --all-features # if docs changed
|
cargo doc --no-deps # if docs changed
|
||||||
cargo publish --dry-run --all-features --allow-dirty # before a release
|
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`.
|
||||||
|
|
||||||
## Architecture Context
|
## Architecture Context
|
||||||
|
|
||||||
- `docs/architecture/` — the authoritative spec. Read it before
|
- `docs/architecture/` — the authoritative spec. Read it before
|
||||||
non-trivial changes. ADRs are numbered; OQs (open questions) track
|
non-trivial changes. ADRs are numbered; OQs (open questions) track
|
||||||
resolved/deferred decisions.
|
resolved/deferred decisions.
|
||||||
- ADR-018 — vault standalone, `EncryptedData` wire format lock
|
- This crate unifies `alknet-call` and `alknet-channels` from the
|
||||||
- ADR-020 — HD derivation for encryption keys, salt unused in v2
|
alknet mono-repo (`/workspace/@alkdev/alknet`). The source
|
||||||
- ADR-021 — key rotation via version-indexed derivation paths
|
architecture docs are at
|
||||||
- ADR-025 — local-only dispatch, no `async`/`tokio`/irpc
|
`/workspace/@alkdev/alknet/docs/architecture/crates/call/` and
|
||||||
|
`/workspace/@alkdev/alknet/docs/architecture/crates/channels/`. They
|
||||||
|
will be ported into `docs/architecture/` here and renumbered as
|
||||||
|
alkcall ADRs (starting at ADR-001).
|
||||||
|
- The source ADRs are in
|
||||||
|
`/workspace/@alkdev/alknet/docs/architecture/decisions/`. Key ADRs
|
||||||
|
that inform this crate's design:
|
||||||
|
|
||||||
|
**Call protocol:**
|
||||||
|
- ADR-064 — hand-rolled `EventEnvelope` framing (irpc never
|
||||||
|
integrated; supersedes ADR-005)
|
||||||
|
- ADR-012 — call protocol stream model (bidirectional streams,
|
||||||
|
ID-based correlation)
|
||||||
|
- ADR-017 — call protocol client and adapter contract (`CallClient`
|
||||||
|
`spawn_dispatch` transport-agnostic; `from_call` imports remote ops;
|
||||||
|
connection direction independent of call direction)
|
||||||
|
- ADR-024 — operation registry layering (curated + session +
|
||||||
|
connection overlays; `OperationEnv` as trait-object integration
|
||||||
|
point)
|
||||||
|
- ADR-029 — peer-graph routing model (peer-keyed overlays +
|
||||||
|
`PeerRef` routing; `AccessControl`-based peer authorization)
|
||||||
|
- ADR-014 — secret material flow and capability injection (no secret
|
||||||
|
material on the wire; capabilities injected at assembly layer)
|
||||||
|
- ADR-015 — privilege model and authority context (`internal` =
|
||||||
|
authority switch not ACL skip; External/Internal visibility)
|
||||||
|
- ADR-016 — abort cascade for nested calls (default
|
||||||
|
`abort-dependents`, `continue-running` opt-in)
|
||||||
|
- ADR-022 — handler registration, provenance, and composition
|
||||||
|
authority
|
||||||
|
- ADR-023 — operation error schemas (typed `details` in `call.error`)
|
||||||
|
- ADR-049 — streaming handler for subscriptions
|
||||||
|
(`StreamingHandler` type, `invoke_streaming()` dispatch path)
|
||||||
|
- ADR-032 — forwarded-for identity (metadata only, never used by
|
||||||
|
`AccessControl::check`)
|
||||||
|
|
||||||
|
**Channels:**
|
||||||
|
- ADR-071 — channels wire format (8-byte chunk header; one-way door)
|
||||||
|
- ADR-093 — channels pure channel multiplexing (no `stream_type`,
|
||||||
|
`BiStream`-only, handler owns sub-stream multiplexing)
|
||||||
|
- ADR-072 — channel 0 pre-negotiated as `alknet/call`
|
||||||
|
- ADR-073 — channel lifecycle operations (`channel/open`/`close`/
|
||||||
|
`control`/`resources/subscribe` on channel 0's call registry)
|
||||||
|
- ADR-075 — `ChannelsAdapter` and `ChannelManager` (substrate-agnostic
|
||||||
|
demux loop; `ChannelManager` is ALPN-blind, auth-blind,
|
||||||
|
transport-blind)
|
||||||
|
- ADR-076 — backpressure, channel limits, ID reuse (bounded-buffer,
|
||||||
|
256-channel per-connection memory bound, monotonic IDs)
|
||||||
|
- ADR-079 — hub relay (translate channel 0, byte-forward data
|
||||||
|
channels with ID rewrite)
|
||||||
|
- ADR-080 — `ChannelClient` (transport-agnostic
|
||||||
|
`from_connection` primary; dial lives in the consumer)
|
||||||
|
- ADR-094 — per-identity channel cap (256 per `PeerId` via
|
||||||
|
`ChannelLifecyclePolicy`)
|
||||||
|
|
||||||
|
**Shared (vendored core types):**
|
||||||
|
- ADR-001 — ALPN-based protocol dispatch
|
||||||
|
- ADR-002 — `ProtocolHandler` trait
|
||||||
|
- ADR-004 — auth as shared core (`IdentityProvider` in core,
|
||||||
|
handlers extract credentials)
|
||||||
|
- ADR-006 — ALPN string convention (`alknet/` prefix, one ALPN per
|
||||||
|
connection)
|
||||||
|
- ADR-007 — `BiStream` type definition (handlers receive
|
||||||
|
`Connection`, not `BiStream`)
|
||||||
|
- ADR-065 — `Connection::from_stream` (generic single-stream
|
||||||
|
connections — unblocks TCP+TLS, SSH, WebTransport, wasm)
|
||||||
|
- ADR-070 — `BidiStreamSource` trait (the `Connection` extension
|
||||||
|
point `ChannelBidiStreamSource` implements)
|
||||||
|
- ADR-092 — `BiStream` as the handler leaf (`accept_bi` returns
|
||||||
|
`BiStream`)
|
||||||
|
|
||||||
- If a TODO references a "Phase B" or a design direction that an ADR
|
- If a TODO references a "Phase B" or a design direction that an ADR
|
||||||
has since decided against, the TODO is stale — remove it and align
|
has since decided against, the TODO is stale — remove it and align
|
||||||
the comments with the ADR. Do not implement the rejected design.
|
the comments with the ADR. Do not implement the rejected design.
|
||||||
|
- The call protocol's `EventEnvelope` shape was derived from the
|
||||||
|
`@alkdev/pubsub` `EventEnvelope`
|
||||||
|
(`/workspace/@alkdev/pubsub/src/types.ts`), which has a working
|
||||||
|
WebSocket client/server implementation. The call protocol refined it
|
||||||
|
with typed event names and structured payloads.
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
This document defines the SDD process for the @alkdev/alkvault package. It
|
This document defines the SDD process for the @alkdev/alkcall package. It
|
||||||
leverages:
|
leverages:
|
||||||
|
|
||||||
- **OpenCode CLI** as the agent execution environment
|
- **OpenCode CLI** as the agent execution environment
|
||||||
|
|||||||
Reference in New Issue
Block a user