The spec docs had not caught up with the stub-sweep fix commits
(4eae18f..3317ea0), and the ported docs still carried alknet
numbering that now collides with alkcall's own ADR range.
Spec sync with the landed code:
- call-protocol.md: register_imported/register_imported_all return
Result and refuse marked specs; marked-spec registration refusal
contract spelled out (ADR-047 am. 4 §4.8, ADR-022 am. 2026-10-13)
- client-and-adapters.md: from_call flow gains the Pub sink-forwarding
branch and the marked-op refusal (resolves OQ-37 — no from_call
relay wrapper; sanctioned compositions are
ChannelRelay::register_relay_openable / ChannelClient)
- ADR-051: "channel/control is not implemented" stale sentence
replaced with the ADR-052 per-leg control contract
- OQ-37 resolved; OQ-22 split (primitive resolved; broker placement
out of scope) with new OQ-42 for the downstream hub broker
(deferred(scope), concretely blocked); OQ-24 resolved by the shipped
add/strip surface; OQ-41 → deferred(scope) with blocking condition
- README: OQ bullets renumbered to tracker IDs; alknet-collision note
rewritten (range 001..053, alknet prefix convention); new principle
11 (implement-or-stop-advertising); AGENTS.md ADR range 001..053
Port-debt repair:
- 149 broken decision links across 17 docs — ported with alknet
numbers/paths, most now remapped to alkcall files by slug; the
rest link the alknet repo per the README convention
- stale OQ numbering rewritten to tracker IDs in call-protocol.md,
call-README.md, operation-registry.md, client-and-adapters.md,
ADR-025, channels-overview/README/wire, channel-client
- unambiguous "alknet ADR-NNN" labels where an alknet number collides
with an alkcall ADR (052 TTY vs channel/control, 033 storage vs
rust-canonical, 025/026/027+020 vault vs PeerEntry/auth ADRs)
Verified: cargo test (697 + guard), fmt, clippy --all-targets -D
warnings; full markdown link scan clean.
- E-03: the open wrapper's handler-exit teardown no longer discards
UnknownChannel silently — debug log + benign-race pinning comment
(ledger take is the atomic gate; no double-decrement)
- E-04: consumer-facing doc note on the 64-parked-chunks observable
bound (channel-client.md + EARLY_ARRIVAL_CAP const doc) for
tunnel-style push-first producers
- N-2: ChannelManager::early_arrival_count() accessor (the
observability choice over removing the write-only counter),
documented monotonic, with a park/adopt-drain monotonicity test
- review 006: Unit 3 marked implemented in Status and remediation plan
Verification: 617 tests pass; clippy -D warnings clean (host +
wasm32 check); fmt clean; doc clean
Implements ADR-049 Unit 1 — the open-op wrapper gains an awaited,
bounded establishment phase, and the client stops erasing the error.
- OpenEstablisher hook + Establishment/EstablishmentError types:
register_openable_with_establisher awaits the establisher bounded
(earlier of dispatch deadline and per-registration timeout, else
ESTABLISHMENT_TIMEOUT = 10s) after allocation, before the reply and
before the pump handler is spawned (ADR-049 §1/§2). Implementation
note: the establisher takes (input, auth) only — the channel's
yield-once BiStream belongs exclusively to the pump handler
(amendment recorded in ADR-049).
- Establishment failure: teardown_channel + opener-ledger take +
policy.on_close un-increment (allocation and teardown balance;
the ledger take is the atomic gate, ADR-047 §7), reply
channel:open_failed with details {reason, message} — reason ∈
dial_failed / unknown_resource / resource_shortage / handler_error
/ timeout (ADR-049 §3). SSH contract consumer-visible: a failed
open never returns a channel_id.
- register_openable unchanged (no establisher = always-OK; existing
registrations compile and behave identically — compat gate test).
- ChannelClient::open_channel returns ChannelOpenError (breaking at
0.5.0): CallFailed { error: CallError } carries the wire error
verbatim (establishment_reason() branches on details.reason);
MissingChannelId / AdoptFailed cover the local-only shapes
(ADR-049 §4, review 006 N-1).
- Tests cover all four verification gates from the review: e2e
establisher failure through a real channels connection (typed
reason + no-channel + ledger un-increment), bounded timeout,
no-establisher compat, establisher-success pump round-trip; plus
reason-vocabulary mapping and bound arithmetic.
- Bump to 0.5.0 (open_channel error-type change is semver-relevant).
Verification: cargo test (608 passed), clippy --all-targets -D
warnings, fmt --check, doc --no-deps, wasm32 check — all clean.