kcode-telegram-identity 0.1.0

Persistent Telegram identity authorization and Kmap-root directory
Documentation
# API

The main types are:

```rust
pub struct Directory { /* private */ }

pub struct User {
    pub handle: String,
    pub telegram_user_id: Option<i64>,
    pub current_username: Option<String>,
    pub display_name: Option<String>,
    pub root_node_id: Option<String>,
    pub root_ready: bool,
    pub can_add_users: bool,
}

pub struct Group {
    pub group_id: String,
    pub root_node_id: Option<String>,
    pub root_ready: bool,
}

pub enum ErrorKind {
    InvalidInput,
    NotFound,
    Conflict,
    Storage,
}
```

`Directory::open(path, bootstrap_handle)` opens or creates the SQLite directory
and ensures that the normalized bootstrap handle is authorized to add users.

Typed directory operations:

```rust
Directory::provisioning_users(&self) -> Result<Vec<User>>
Directory::provisioning_groups(&self) -> Result<Vec<Group>>
Directory::user(&self, telegram_user_id: i64) -> Result<User>
Directory::group(&self, group_id: &str) -> Result<Group>
Directory::complete_handle_root(&self, handle: &str, root: NodeId) -> Result<User>
Directory::complete_user_root(&self, user_id: i64, root: NodeId) -> Result<User>
Directory::complete_group_root(&self, group_id: &str, root: NodeId) -> Result<Group>
```

`Directory` implements `kcode_tg_kennedy_bot::IdentitySink`. The Telegram
transport uses that interface to report observed identities and groups, obtain
the stable numeric whitelist, and request delegated additions.

Root creation remains the caller's responsibility. Completion operations only
record an already-created canonical Kweb node ID and reject reassignment.