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.
- open-questions.md: OQ-39 → ADR-052, OQ-40 → ADR-053 (resolutions replace
the deferred-until-needed posture)
- channel-operations.md: the put contract (initiator allocates + streams,
reserved input key, one response, acks-in-result sentence), the control
routing (ADR-052), the enumerator aggregation (ADR-053), the
connection-owner paragraph's pub-era correction, the ADR table rows
- ADR-051 §6: PubTypedOpen → the put translation; ADR-047's 2026-09-06
amendment records its era honestly (the dynamic half is now ADR-053)
- review 010: all four findings resolved (with the S-01 sketch correction
so the published record stops carrying the wrong-graph reading)
- review 011: closed (all seven pins implemented + gates landed)
- review 001 C-08: resolved note (odd/even + adopt, implemented)
- AGENTS.md: the 'Stub Guard' section — the not_implemented grep is part
of cargo test; the registration invariants and the implement-or-stop
ruling are release-blocking
Verified: cargo test (696+guard), clippy -D warnings, fmt, doc clean.
- architecture README: index rows for ADR-049 (establishment phase) and
ADR-050 (pump_bidi); stale ADR-001..045 range labels corrected
- channel-operations.md: design-decision table + references list the
two new ADRs
- CHANGELOG: missing link references for 0.4.0/0.4.1/0.5.0/0.6.0
- AGENTS.md: ADR range 001..050
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.