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.
Verifies and fixes CF-005 (alktunnels reverse-flow POC W1): the
connect-side serving path built channel 0 internally and never set an
identity, so a scope-gated serving op could only be satisfied via the
payload auth_token. Token is now the fallback (hub-forwarding /
browser path); transport/key-based identity is the primary path.
- ServingConfig gains identity: Option<Identity> — the explicit
override (remediation a). Semver-relevant struct-literal change →
0.7.0 (minor bump at 0.x, wire surface unchanged).
- from_connection_with_serving propagates the transport
Connection::identity() to the channel-0 connection via set_identity
before the serving loop starts (remediation b) — mirrors the accept
side's install-hook set_identity; process-local, nothing new on the
wire.
- Dispatch identity precedence on the serving loop: payload
auth_token → identity_provider, then ServingConfig.identity, then
transport identity; identity-less dispatch still fails closed
(FORBIDDEN).
- Public core::auth::NoopIdentityProvider (resolves nothing; the
ServingConfig::default() provider — three private test copies
existed).
- Regression gates: four cf005_* e2e tests (transport propagation,
override precedence, identity-less denial, token fallback +
precedence).
- Ledger CF-005 → resolved; ADR-022 §connect-side-serving amended;
README example updated; changelog 0.7.0.
Verification: cargo test (629) + --all-features (646), clippy
(all-targets, all-features, -D warnings), fmt --check, doc
--no-deps, wasm32 check, semver-checks (no update required at
0.7.0), publish --dry-run.
- resource_id_path rides both halves of the spec wire round-trip:
spec_to_json_pub serializes it (optional string key), rebuild_spec_for
parses it. Additive optional field - absent stays absent. Previously
an announced (or from_call-imported) op declaring ownership-scoped
resource extraction silently rebuilt with resource_id: None, so ACL
checks ran without the resource ID.
- Gates: spec_round_trips_resource_id_path (serialize -> parse ->
field intact) + spec_without_resource_id_path_stays_absent (additive
field breaks no consumer).
- ADR-022 amendment: bootstrap-op set gains services/list-peers with a
dated G-05 note (the installer has registered it since the amendment
landed; the doc lagged the code). Set remains closed at four.
Verification: cargo test 589 / --all-features 606, clippy
(all-targets, all-features, wasm32) clean, fmt clean, doc clean.
Refs docs/reviews/005-...md (G-04, G-05; all findings closed).
- op_register_handler takes the serving registry alongside the
connection and rejects announced names that collide with the serving
side's own registrations (ALREADY_EXISTS regardless of replace).
Peer-announced ops may collide with peer-announced ops (replace
governs, the reconnect path) but never shadow the deployment's own
ops: the connection overlay resolves before base in PeerCompositeEnv,
so an unscreened same-name announce would silently rewrite what a
wire-dispatched handler's ctx.env.invoke resolves. Composition
authority (ADR-018) stays with the deployer.
- ADR-022 amendment (2026-09-04): collision policy recorded in the
2026-09-03 amendment's op/register section (rationale + visibility
irrelevance); status line notes the sub-amendment.
- Gates: base-External collision rejected even with replace (overlay
stays clean, serving registration untouched); Internal base op
equally protected; overlay/overlay collisions still follow replace;
nested composition of a base op resolves the serving side's own op
after an unrelated announce (real compose_root_env env shape).
- PeerCompositeEnv resolution order deliberately unchanged.
Verification: cargo test 587 / --all-features 604, clippy
(all-targets, all-features, wasm32) clean, fmt clean, doc clean.
Refs docs/reviews/005-...md (G-03; Unit 3 open).