- definitions.md: formal term disambiguation for overloaded concepts (service, interface, token, identity, domain) with cross-domain mapping tables (alknet ↔ Keystone, distributed git, rustfs) and 8 open questions - references/rustfs/: research on rustfs S3 store, Keystone/OIDC integration, and credential mapping to CredentialSet - references/gitserver/: research on gitserver library architecture and integration paths as HTTP MessageInterface and SSH adapter - references/openstack-keystone/: research on Keystone identity concepts (tokens, scoping, service catalog, RBAC, trust delegation, federation) and what alknet should adopt vs skip - references/distributed-identity/: research on decentralized git, smart contract ACL, on-chain identity, and Radicle comparison
33 KiB
Definitions: Terminology Disambiguation and Concept Mapping
Status: Research / Draft Last updated: 2026-06-08 Part of: Phase 2 planning
Purpose
Multiple terms are overloaded across alknet's architecture, OpenStack's identity model, and the distributed systems/git space. This document disambiguates each term, maps equivalent concepts across domains, and identifies open questions that need resolution before updating architecture specs.
The architecture docs (interface.md, auth.md, services.md) reflect a pre-Phase-0/1 state. This document exists to untangle conceptual knots before editing those specs.
Term Definitions
Interface (alknet Layer 2)
Definition: An interface consumes a byte stream from a Transport (Layer 1) and produces call protocol sessions or handles discrete requests. It is a protocol parser, not a network service.
Subtypes:
| Subtype | Trait | Lifecycle | Transport ownership | Examples |
|---|---|---|---|---|
StreamInterface |
StreamInterface::accept(stream) -> Session |
Long-lived session | Provided by caller | SshInterface, RawFramingInterface |
MessageInterface |
MessageInterface::handle_request(req) -> Response |
Stateless per-request | Self-managed | HttpInterface, DnsInterface, WebSocketInterface |
Not to be confused with: A "service interface" (API surface of a service), a Rust trait (also called an interface generically), or an "interface" in the OpenStack sense (a network endpoint).
Source: interface-model.md
Transport (alknet Layer 1)
Definition: A transport produces a byte stream (AsyncRead + AsyncWrite + Unpin + Send) or a datagram channel. It is a wire mechanism, not a protocol. Transports are listed in TransportKind: TCP, TLS, iroh (QUIC), WebTransport.
Not to be confused with: The HTTP transport (which is a transport+interface combined in a MessageInterface), or the DNS "transport" (which was removed from TransportKind because DNS is a MessageInterface).
Key constraint: A connection is always a (Transport, StreamInterface) pair for stream-based connections. MessageInterface implementations manage their own transport internally.
Source: tls-transport.md, interface-model.md
Service (irpc service)
Definition: An in-cluster Rust-to-Rust service defined by an irpc protocol enum. Services are dispatched by enum variant and use postcard serialization. They run within a node or cluster and are synchronous request-response.
Examples: AuthProtocol, SecretProtocol, ConfigProtocol, StorageProtocol.
Not to be confused with: A call protocol operation (path-based, JSON, cross-node), an external service (a third-party endpoint reachable via HTTP/call protocol), or an application service (DockerService, GitService — an operation-registered handler).
Architecture position: irpc services are one dispatch backend for OperationEnv, not a replacement for it.
Source: integration-plan.md, Inconsistencies section item 3.
Operation (call protocol)
Definition: A path-based handler registered in the OperationRegistry, dispatched by namespace + name (e.g., /head/auth/verify). Operations are cross-node, cross-language, and use JSON EventEnvelope frames.
Not to be confused with: An irpc service method (which is dispatched by enum variant, not path), or an OpenStack operation (which is a REST API verb).
Architecture position: Operations are the universal composition unit. All interfaces (SSH, HTTP, DNS, WebSocket, MCP) resolve to the same operation invocations through OperationEnv.
Source: integration-plan.md, ADR-033.
External Service
Definition: Any endpoint reachable via the call protocol from another node or over an interface — an HTTP API (vast.ai), another alknet head node, rustfs, gitea. External services are consumed by alknet, not part of it.
Examples: vast.ai cloud API, runpod API, any OpenAPI-described endpoint consumed by OpenAPIServiceRegistry.
Not to be confused with: An irpc service (internal), or an application service (handler within alknet).
Application Service
Definition: A handler registered with the OperationRegistry that provides application-level functionality. Application services are pluggable, don't change core, and register operations like any other handler.
Examples: DockerService, NodeService, GitService, RustfsService.
Not to be confused with: An irpc service (which is a dispatch mechanism, not a handler), or an external service (outside the cluster).
Identity (alknet core type)
Definition: A struct { id, scopes, resources } that represents an authenticated principal. Produced by IdentityProvider::resolve_from_fingerprint() or IdentityProvider::resolve_from_token(). The same person connecting via SSH key or API token resolves to the same Identity (same id in database-backed deployments).
Mapping to other domains:
| alknet Concept | OpenStack Keystone | Distributed Git |
|---|---|---|
Identity.id (fingerprint or UUID) |
User ID | Radicle DID / on-chain address |
Identity.scopes |
Role assignments on a project/domain | Repository ACL entries |
Identity.resources |
Service catalog endpoints | Repositories accessible |
IdentityProvider |
Keystone identity service | On-chain registry + local cache |
Not to be confused with: A "user" (which is an account concept in storage), a "principal" (similar but not identical — an Identity can represent a service account or API key).
Source: identity.md, auth.md, ADR-029.
IdentityProvider (alknet trait)
Definition: A trait in alknet_core::auth with two methods: resolve_from_fingerprint() (SSH key auth) and resolve_from_token() (bearer token auth). It resolves an inbound credential to an Identity.
Implementations: ConfigIdentityProvider (ArcSwap-backed, minimal), StorageIdentityProvider (SQLite-backed, production). Future possibility: OnChainIdentityProvider (smart contract + local cache).
Direction: Inbound (who is calling alknet).
Not to be confused with: CredentialProvider (outbound — how alknet authenticates TO external services), or an OpenStack Keystone "identity provider" which is a federation concept.
CredentialProvider (alknet trait)
Definition: A trait in alknet_core::credentials that resolves outbound credentials. get_credentials(service) -> Option<CredentialSet>. It answers: "how does alknet authenticate to service X?"
Direction: Outbound (how alknet calls external services).
Mapping: Rustfs credentials (S3AccessKey), gitea tokens (Bearer), OIDC tokens (OidcToken), API keys (ApiKey).
Not to be confused with: IdentityProvider (inbound auth resolution).
Source: credential-provider.md
AuthToken (alknet wire format)
Definition: base64url(key_id || timestamp || signature) — an Ed25519-signed timestamp token used for non-SSH auth (HTTP, DNS, WebTransport, WebSocket).
Mapping to other domains:
| alknet | OpenStack Keystone | Description |
|---|---|---|
| AuthToken | Keystone token (X-Auth-Token) | Proof of identity carried in a request |
| AuthToken (Ed25519 signed) | Keystone token (scoped, with catalog) | Keystone tokens carry more metadata (catalog, scope); alknet tokens are minimal |
API key (alk_...) |
Application Credential | Password-less auth with restricted scope |
resolve_from_token() |
Token validation endpoint | Verify token → resolve identity |
Key difference: Keystone tokens are server-issued and carry scope/catalog. alknet AuthTokens are self-signed (client-generated) and carry only key_id + timestamp — scope is resolved server-side by IdentityProvider. This is intentional: alknet doesn't need a token issuance endpoint because tokens are self-proving.
Source: auth.md, ADR-023.
Domain Event vs Integration Event
Definition (from event-sourcing/event_source_types.md):
| Type | Scope | Consumers | Serialization | Example |
|---|---|---|---|---|
| Domain Event | Within a single service boundary | Internal handlers only | Can be rich, domain-specific | InventoryAdjusted, KeyRotated |
| Integration Event | Across service boundaries | External services, other nodes | Simple, versioned, stripped of internals | call.requested (EventEnvelope), UserCreated (projected) |
alknet mapping:
| Boundary | Mechanism | Serialization | Scope |
|---|---|---|---|
| Within a service (e.g., AuthProtocol) | Honker streams (domain events) | Internal | Same service |
| Between services in a cluster | irpc protocol enum | postcard (binary) | Same cluster |
| Between nodes or over interfaces | Call protocol EventEnvelope | JSON | Cross-node |
Hard constraint (ADR-032): Domain events never cross service boundaries without projection. Integration events are the boundary contract.
Not to be confused with: A "call protocol event" (which IS an integration event), or a "service call" (which is synchronous, not event-based).
Scope (alknet)
Definition: A permission or claim attached to an Identity. Used by ForwardingPolicy and operation-level ACL. Defined as part of the Identity struct.
Mapping to other domains:
alknet Scope |
OpenStack Keystone | Distributed Git |
|---|---|---|
scopes: ["relay:connect", "secrets:derive"] |
Role assignments on a project ("member", "admin") | Write/push access to repository X |
resources: [...] |
Project/domain scope targets | Which repositories are accessible |
Open question: Should alknet adopt a richer scope model (hierarchical, like Keystone's implied roles), or keep the flat string model? See OQ-DEF-03.
OperationRegistry (alknet)
Definition: The central registry that maps (namespace, operation_name) to handlers. All interfaces resolve to the same registry. The HTTP interface maps POST /v1/{namespace}/{op} to registry.invoke(). The call protocol maps call.requested with operationId to registry.invoke().
Mapping to other domains:
| alknet | OpenStack Keystone | Description |
|---|---|---|
| OperationRegistry | Service Catalog | Both map names to endpoints; registry is programmatic, catalog is runtime-discovered |
FromOpenAPI |
— | Consumes an external API spec and registers operations |
GET /v1/schema (proposed) |
GET /v3/auth/catalog |
Produces a spec of available operations |
Key difference: Keystone's catalog is per-token (scoped to the user's project). alknet's OperationRegistry is global — scope checking happens at invocation time, not discovery time.
Call Protocol (alknet Layer 3)
Definition: The application-level protocol that carries operations, events, and responses between nodes. Uses JSON EventEnvelope frames. Interface-agnostic: runs over any (Transport, StreamInterface) pair or any MessageInterface.
Not to be confused with: irpc service calls (synchronous, in-cluster, postcard), or HTTP (which is an interface that maps to call protocol operations).
Concept Mapping Table
Alknet ↔ OpenStack Keystone
| Alknet Concept | Keystone Equivalent | Notes |
|---|---|---|
Identity |
User + Role Assignment + Project scope | alknet is simpler; Keystone separates user/role/project |
Identity.id |
User ID | In storage-backed: UUID. In config-backed: key fingerprint |
Identity.scopes |
Role assignments | alknet uses flat strings; Keystone uses hierarchical roles |
Identity.resources |
Project scope + Service Catalog | Both limit what a token can access |
IdentityProvider |
Keystone identity service | Both resolve credentials → identity + scope |
AuthToken |
Keystone token (X-Auth-Token) | alknet tokens are self-signed (no issuance endpoint); Keystone tokens are server-issued |
API key (alk_...) |
Application Credential | Nearly identical pattern |
CredentialProvider |
— (no direct equivalent) | Keystone doesn't authenticate outbound; each service manages its own credentials |
OperationRegistry |
Service Catalog | Registry is programmatic; catalog is runtime-discovered per-token scope |
CredentialSet::S3AccessKey |
S3 credential (access key + secret) | Directly maps to rustfs IAM model |
CredentialSet::OidcToken |
Federated token | alknet Phase D: becomes OIDC provider |
| Domain events (Honker) | — | Internal event bus, no Keystone equivalent |
| Integration events (call protocol) | Keystone notifications | Both are cross-boundary, but call protocol is request/response, not pub/sub |
| Token scoping | Unscoped → scoped token flow | alknet resolves scope server-side; Keystone requires explicit scope request |
Alknet ↔ Distributed Git / Smart Contracts
| Alknet Concept | Distributed Git Equivalent | Notes |
|---|---|---|
Identity.id (Ed25519 fingerprint) |
Radicle DID (Ed25519 pubkey hash) | Both use Ed25519; alknet uses SLIP-0010 derivation |
Identity.scopes |
Repository ACL entries | Smart contract: NFT ownership → write permission |
IdentityProvider |
On-chain identity registry | alknet: local/DB lookup. Distributed: on-chain verification + local cache |
CredentialSet |
Git push credentials | ssh-key for SSH git, token for HTTPS git |
| Call protocol (integration events) | Gossip protocol (Radicle) | Both are cross-node; call protocol is point-to-point, gossip is epidemic |
OperationRegistry |
Replicator registry (on-chain) | Both map names to endpoints/operations |
| Domain events (Honker) | Git ref updates (internal) | Internal to the git service boundary |
| Seed derivation (BIP39) | Ethereum private key | Both derive multiple keys from one seed; different curves (Ed25519 vs secp256k1) |
| SecretProtocol key paths | — | alknet's m/74'/0'/0'/0' for Ed25519 identity; m/44'/60'/0'/0/0 for Ethereum signing |
Alknet ↔ Rustfs Auth Integration
| Alknet Concept | Rustfs Equivalent | Integration Path |
|---|---|---|
IdentityProvider (inbound) |
Rustfs IAM / Keystone auth | Phase D: alknet as OIDC provider → rustfs accepts alknet tokens |
CredentialSet::S3AccessKey |
Rustfs access key + secret key | Phase A: static credentials; Phase C: per-identity provisioned keys |
CredentialProvider (outbound) |
Rustfs admin API (key provisioning) | Phase C: ManagedCredentialProvider provisions rustfs keys |
Identity.scopes |
Rustfs IAM policy | Phase D: scope → OIDC claim → policy mapping |
| HTTP MessageInterface | Rustfs S3 API (port 9000) | Rustfs sits behind alknet's HTTP router or sidecar |
| OperationRegistry | — | Git service maps git.clone, git.push, etc. to operations |
Overloaded Terms: Disambiguation
"Service" — Three Meanings
| Context | Meaning | Example | Architecture Layer |
|---|---|---|---|
| alknet irpc service | In-cluster Rust-to-Rust protocol enum | AuthProtocol, SecretProtocol |
Layer 3 (internal) |
| alknet application service | Operation-registered handler | GitService, RustfsService |
Layer 3 (handler) |
| External service | Third-party endpoint consumed by alknet | vast.ai, rustfs instance |
Outside alknet (consumed via OperationEnv) |
Rule: When ambiguity is possible, use the full qualifier: "irpc service", "application service", or "external service". The bare word "service" should be avoided in architecture docs.
"Interface" — Three Meanings
| Context | Meaning | Example |
|---|---|---|
| alknet Layer 2 | A protocol parser that consumes Transport streams or handles discrete requests | SshInterface, HttpInterface, DnsInterface |
| Rust/generic | A trait definition | IdentityProvider, CredentialProvider |
| OpenStack/generic | A network endpoint (URL) for a service | Keystone's public/internal/admin interfaces |
Rule: In alknet architecture docs, "Interface" (capitalized) refers to Layer 2. "trait" or "contract" should be used for Rust trait definitions. "endpoint" should be used for network URLs.
"Token" — Three Meanings
| Context | Meaning | Structure |
|---|---|---|
| AuthToken (alknet) | Self-signed Ed25519 timestamp | base64url(key_id || timestamp || sig) |
| API key (alknet) | Hash-verified bearer string | alk_... prefix, SHA-256 hash verification |
| Keystone token | Server-issued scoped token | UUID or JWT, carries catalog and scope |
Rule: "AuthToken" refers to alknet's self-signed token. "API key" refers to the hash-verified bearer format. "Keystone token" when referring to OpenStack. Never use bare "token" in architecture docs.
"Identity" — Two Meanings
| Context | Meaning |
|---|---|
alknet Identity struct |
{ id, scopes, resources } — the authenticated principal |
| OpenStack Identity (Keystone) | The entire identity management SERVICE, including users, projects, roles, tokens, catalog |
Rule: "Identity" (capitalized, code font) = alknet struct. "Keystone" or "identity service" = OpenStack concept.
"Domain" — Two Meanings in Event Sourcing
| Context | Meaning |
|---|---|
| Domain Event | An event within a single service boundary (e.g., KeyRotated within AuthProtocol) |
| DNS Domain | A domain name in DNS queries/records |
These are unrelated. "Domain event" is from DDD. "DNS domain" is from networking. Context should always make it clear, but if there's any chance of confusion, use "bounded-context event" instead of "domain event".
Architectural Patterns: Cross-Domain Comparison
Pattern: Inbound Auth → Outbound Credentials
┌──────────────────────────────────────────────────────────────┐
│ Incoming Request │
│ │ │
│ ▼ │
│ IdentityProvider │
│ (credential → Identity) │
│ │ │
│ ├── SSH fingerprint → Identity.id, .scopes, .resources │
│ ├── Bearer AuthToken → Identity.id, .scopes, .resources │
│ └── API key → Identity.id, .scopes, .resources│
│ │ │
│ ▼ │
│ OperationContext { identity, env, ... } │
│ │ │
│ ├── context.env.invoke("git", "push", input) │
│ │ └── GitService handler │
│ │ └── CredentialProvider │
│ │ └── get_credentials("rustfs") │
│ │ └── S3AccessKey { access_key, │
│ │ secret_key } │
│ │ │
│ └── context.env.invoke("secrets", "derive", input) │
│ └── local dispatch to SecretProtocol │
│ │
│ Two directions: Inbound (who is calling us) │
│ Outbound (how we call others) │
└──────────────────────────────────────────────────────────────┘
Pattern: Scope Resolution Across Systems
| System | Scope Source | Scope Shape | Scope Check Location |
|---|---|---|---|
| alknet (current) | IdentityProvider |
Flat strings ["relay:connect"] |
Handler invocation |
| Keystone | Role assignment on project | Hierarchical roles with implied roles | Policy engine per service |
| Rustfs IAM | Policy document attached to user | JSON policy with actions/resources | Request evaluation |
| Smart contract ACL | NFT ownership + on-chain mapping | Address → repo → permission level | On-chain verification + local cache |
| Radicle | Local config | Pubkey → repo → permission | Pre-receive hook |
Open question: Should alknet adopt hierarchical implied roles (Keystone pattern) or stay with flat scopes and let individual services interpret them?
Pattern: Token Self-Proving vs Server-Issued
| Property | alknet AuthToken | Keystone Token | API Key |
|---|---|---|---|
| Issued by | Client (self-signed) | Server (Keystone) | Admin (config or DB) |
| Carries | key_id + timestamp + signature | User ID, scope, catalog, expiry | Prefix + hash |
| Verified by | Ed25519 signature check | Server lookup (database or JWT) | SHA-256 hash check |
| Revocation | Key removal from authorized_keys |
Token revocation list or JWT jti |
DB deletion |
| Scope resolution | Server-side (IdentityProvider) | Embedded in token | Server-side (DB lookup) |
| Replay protection | Timestamp window (±300s) | Token TTL + server validation | N/A (stateless) |
alknet's self-proving model avoids the need for a token issuance endpoint. This is a deliberate trade-off: simpler at the cost of no server-side session state. For replay protection beyond the timestamp window, future work could add nonce challenge-response (ADR-023).
Service Classification
Services within alknet's ecosystem are classified by their relationship to the core:
Core Services (irpc, always present when feature flag enabled)
| Service | Protocol | Location | Purpose |
|---|---|---|---|
| Auth | AuthProtocol |
alknet-core (irpc feature) |
Identity resolution, credential verification |
| Config | ConfigProtocol |
alknet-core (irpc feature) |
Dynamic config reload |
| Secret | SecretProtocol |
alknet-secret | Key derivation, encryption, decryption |
| Storage | StorageProtocol |
alknet-storage | Metagraph CRUD, ACL, accounts |
Application Services (operation-registered, pluggable)
| Service | Interface | Core dependency | Purpose |
|---|---|---|---|
| GitService | HTTP (MessageInterface) + SSH (StreamInterface) | IdentityProvider, CredentialProvider | Git clone/push/pull over HTTPS and SSH |
| RustfsService | HTTP (MessageInterface) | CredentialProvider | S3-compatible object storage proxy |
| DockerService | HTTP (MessageInterface) | CredentialProvider | Container management |
| NodeService | HTTP (MessageInterface) | IdentityProvider | Node management |
External Services (consumed, not hosted)
| Service | Integration | Auth |
|---|---|---|
| vast.ai | OpenAPIServiceRegistry + CredentialProvider |
API key |
| runpod | OpenAPIServiceRegistry + CredentialProvider |
API key |
| ubicloud | OpenAPIServiceRegistry + CredentialProvider |
API key |
Key distinction: Rustfs and gitea are "self-hosted external services" — they run inside the same deployment boundary but are managed independently. alknet acts as a gateway (identity provider, credential provider) and reverse proxy (HTTP interface) for them, but they are NOT part of alknet-core.
Open Questions
OQ-DEF-01: Should alknet adopt a "Service Catalog" concept like Keystone?
Keystone's service catalog lets a token carry information about which services and endpoints are available to the authenticated user. alknet's OperationRegistry is global — every authenticated identity sees the same operations. Should there be a scope-filtered operation discovery mechanism?
Options:
- Keep
OperationRegistryglobal, check scope at invocation time (current design) - Add
GET /v1/catalogorGET /v1/schema?scope=<scope>that returns only operations the identity can invoke - Add a "service catalog" field to
Identity.resourcesthat lists available namespaces
Recommendation: Start with option 1 (current design). Add option 2 when multi-tenant deployment requires it. The GET /v1/schema endpoint (from tls-transport.md) already provides operation discovery — adding scope filtering is additive.
OQ-DEF-02: Should "application service" and "irpc service" be renamed to avoid "service" overloading?
The word "service" has three meanings in the architecture (irpc, application, external). Should we adopt different terms?
Options:
- Keep current names, always qualify with "irpc service", "application service", "external service"
- Rename: "irpc service" → "irpc protocol" or "backend handler"; "application service" → "adapter" or "integration"
- Adopt the call-protocol terminology exclusively: everything that registers in
OperationRegistryis an "operation handler", and "service" refers only to external endpoints
Recommendation: Option 1 for now. The qualifiers are sufficient, and renaming would require changing ADRs and multiple specs. Revisit if confusion persists in practice.
OQ-DEF-03: Should Identity.scopes be hierarchical (like Keystone implied roles) or stay flat?
Current design: scopes: Vec<String> with flat strings like "relay:connect", "secrets:derive".
Keystone pattern: Roles can imply other roles (admin implies member). Policies are per-service, not global strings.
Options:
- Keep flat scopes, let individual services interpret them (current)
- Add implied scope resolution:
"admin"→["relay:connect", "secrets:derive", ...] - Adopt a policy language (JSON policy documents like Rustfs IAM)
Recommendation: Start with option 1. Add implied scope resolution in alknet-storage when multi-tenant deployment requires it. A full policy language is Phase D territory and should follow what Rustfs already uses (MinIO-style JSON policies) rather than inventing something new.
OQ-DEF-04: How should the GitService adapter work across HTTP and SSH?
gitserver provides gitserver-core (transport-agnostic git protocol logic) and gitserver-http (Axum HTTP layer). alknet's architecture supports two paths:
Path A — HTTP MessageInterface: Git operations over HTTPS, with alknet's HTTP interface authenticating the request and passing Identity to the GitService handler. The GitService handler uses Identity to determine repo access and calls gitserver-core directly.
Path B — SSH StreamInterface: Git operations over SSH, where the SSH interface already authenticates the user. Git commands are dispatched through SSH channels (similar to how channel_open_direct_tcpip works for port forwarding, but with a git-upload-pack / git-receive-pack channel type).
Path C — Both: gitserver-core as the protocol engine, gitserver-http for HTTPS, and a custom SshGitInterface for SSH-git channels.
Recommendation: Phase 1 — Path A (HTTP only). Phase 2 — Path C (both). The git-smart-HTTP-protocol is well-understood, and gitserver-http can be nested into alknet's Axum router. SSH git requires designing a new channel type in SshInterface.
OQ-DEF-05: Should alknet act as an OIDC provider (Phase D of credential-provider.md)?
This is the most cross-cutting question. If alknet becomes an OIDC provider, it becomes the identity backbone for all self-hosted services (rustfs, gitea, etc.). This maps to OpenStack Keystone's role but with a different scope model.
Benefits:
- Eliminates stored credential management for OIDC-compatible services
- Users authenticate once via alknet (SSH key or token) and get scoped access to all services
- Maps directly to
Identity.scopes → OIDC claims → service policies
Complexity:
- Requires OIDC authorization server endpoints (authorize, token, userinfo, jwks)
- Requires PKCE flow for browser-based auth
- Requires claim → policy mapping per service
- alknet is not currently designed to be an OIDC server
Recommendation: Phase D (long-term). Phases A-C use static credentials and managed credentials, which are sufficient for most deployments. OIDC provider is a quality-of-life improvement that becomes important in multi-user self-hosted setups.
OQ-DEF-06: How does Domain Event vs Integration Event discipline apply to self-hosted services?
ADR-032 says domain events stay within the service boundary and integration events cross it. Rustfs and gitea are outside alknet's boundary but inside the deployment boundary. Where do their events fall?
Options:
- Self-hosted services are external: their events are integration events, consumed via callback/webhook
- Self-hosted services are part of alknet's boundary: use Honker streams internally, project to integration events for cross-node
- Hybrid: alknet projects rustfs/gitea state changes into
EventEnvelopeintegration events, but rustfs/gitea internal events stay in their own boundary
Recommendation: Option 3. Self-hosted services have their own internal event systems. alknet projects state changes (bucket created, repo pushed) into EventEnvelope integration events for cross-node communication. Honker streams are for events within alknet-core services only.
OQ-DEF-07: How should the smart-contract / on-chain identity model relate to alknet's IdentityProvider?
The distributed git concept (NFT-based org/repo tokens) introduces a third IdentityProvider implementation that validates identity on-chain. How does this relate to the existing two implementations?
Option 1 — OnChainIdentityProvider: A new implementation of the IdentityProvider trait that checks on-chain ownership. Slow path: on-chain verification (0.5-5s on L2). Fast path: local ACL metagraph cache validated against on-chain state periodically.
Option 2 — Separate verification layer: On-chain verification is a separate step, not an IdentityProvider. After normal auth (SSH key or token), a second check verifies on-chain ownership for specific operations (e.g., write to a distributed repo).
Option 3 — CredentialProvider extension: On-chain verification is outbound — alknet authenticates TO the smart contract to verify repo permissions. This would be a new CredentialSet variant.
Recommendation: Option 1 for the long term. The IdentityProvider trait is designed to be pluggable. An OnChainIdentityProvider with local cache is additive. It resolves on-chain identity to an Identity struct just like ConfigIdentityProvider and StorageIdentityProvider. The seed derivation path m/44'/60'/0'/0/0 (Ethereum) alongside m/74'/0'/0'/0' (Ed25519 identity) provides a cryptographic link between the two key types.
OQ-DEF-08: Should the "interface" concept in auth.md (which distinguishes auth "presentation" per transport/interface pair) be renamed to avoid confusion with Layer 2 "Interface"?
In auth.md, "auth presentation" is the mechanism by which credentials are presented on each interface:
- SSH: key handshake
- HTTP: Bearer header
- DNS: token in query labels
- WebTransport: token in CONNECT request
This is NOT the same as "Interface" (Layer 2), but uses the same word. Should we adopt a distinct term?
Options:
- Keep "auth presentation" — it's already distinct from "Interface" (Layer 2)
- Rename to "auth mechanism" or "credential presentation" to be more precise
- Use the term from the interface-model.md table: "(Transport, Interface) → Auth mechanism"
Recommendation: Option 2. "Credential presentation" is precise and doesn't overload "interface". Update auth.md to use "credential presentation per (Transport, Interface) pair" consistently.
References
- interface-model.md — StreamInterface / MessageInterface trait design
- credential-provider.md — CredentialProvider, CredentialSet (outbound auth)
- tls-transport.md — Unified multi-interface architecture
- integration-plan.md — Phase structure, OperationEnv, event boundary discipline
- identity.md — Identity struct, IdentityProvider trait
- auth.md — Unified auth, AuthToken format
- services.md — irpc services, OperationEnv
- event-source-types.md — Domain events vs integration events
- ADR-032 — Event boundary rule
- ADR-033 — OperationEnv, three dispatch paths
- references/rustfs/ — Rustfs research and reference
- references/gitserver/ — Gitserver research and reference
- references/openstack-keystone/ — OpenStack Keystone concepts
- references/distributed-identity/ — Distributed identity and smart contract ACL