kcode-kennedy-app 0.5.13

Security-reviewed Kennedy application composition and lifecycle
Documentation
# Kennedy application contract

This library is Kennedy's security-sensitive top-level application composition
and lifecycle boundary. It owns command dispatch, the process-level maintenance
guard, runtime-directory preparation, construction of in-process capabilities,
root and runtime-model selection, listener ordering, and lifetime supervision.
Mechanical argument parsing and stable path defaults are delegated to the CLI
boundary. Fixed secret-name policy, credential-vault prompting and mutation,
required and optional secret resolution, and Kweb signing-configuration parsing
are delegated to the bootstrap-secret boundary.

Task state defaults to `./data/kennedy-task-board.sqlite3`; the separate credit
balance capability defaults to `./data/kennedy-credits.sqlite3`. Startup opens
credits first, passes that handle into the task board, and shares the resulting
handles with the read-only HTTP presentation and Kennedy session services.

The executable wrapper delegates directly to this library. Application behavior
belongs here or in a focused lower-level library, never in that wrapper. Static
prompts have no prompt-directory configuration or runtime prompt-file
dependency. The composed prompt excludes the `DehydrateBoxes`, `SummarizeBox`,
and `HydrateBox` manuals; native tool registration and Root-loadable Kmap
context-management instructions are separate concerns.

## Public API

### `main`

```rust
pub async fn main() -> anyhow::Result<()>
```

`main` is the complete Kennedy process entry point. It installs tracing and the
Rustls ring crypto provider, parses the process arguments, and executes exactly
one requested maintenance command or normal server startup.

Secret maintenance binds the configured public listener address before reading
or mutating the vault. An occupied address returns an error directing the
operator to stop the running server. `Set` preserves the supplied name, prompts
without echo for an existing-vault passphrase or twice for a new matching,
nonempty passphrase, then twice for a matching, nonempty value before saving.
`Remove`, `List`, and `ChangePassphrase` return the established no-vault message
without prompting when the vault path is absent. Successful changes are saved
before their success lines are printed. Listing prints names in vault iteration
order and never prints values. Empty or mismatched duplicate inputs are rejected
and their input buffers are zeroized.

Kmap-size maintenance acquires the same listener guard, prompts once with
`Unlock Kennedy credential vault: `, reads the configured vault, parses the two
Kweb signing values, measures the configured Kweb root, and prints the complete
rendered result. It does not truncate that result.

Normal startup binds the public listener before creating directories or opening
persistent state. It then creates missing parents for configured runtime paths,
using mode `0700` for newly created directories on Unix, and unlocks the vault.
A missing vault emits a warning containing its path and behaves as an empty
vault. The fixed optional names are `openai-api-key`, `gemini-api-key`, and
`telegram-bot-token`; an absent optional value emits a warning naming the secret
and purpose and disables only that feature. The required names are
`cratesio-key`, `kweb-writer-signing-key`, and
`kweb-writers-by-priority`; an absent required value returns an error naming the
purpose, secret, and `kennedy-server secrets set` remedy.

Secret values and passphrases are never logged. The Kweb signing key must trim
to hexadecimal that decodes to exactly 32 bytes. The ordered writer list is
comma-separated: entries are trimmed, empty entries are ignored, order is
preserved, every retained entry must parse as a writer identifier, and the
result must not be empty. Kweb gossip is no-op. Accepted provider and publication
values become ordinary owned strings because their consumers require that
representation, so dropping those strings does not guarantee zeroization.

After secret resolution, server startup opens Kweb and its canonical roots,
constructs the durable administrator command lane, credits and task state,
identity, history, intelligence, agent, Telegram, audio, developer-tool, HTTP,
session-control, root-reconciliation, general orchestration, and Telegram
session capabilities, then supervises the HTTP server and four long-running
runtime futures in one async try-join. The listener is not served until
construction succeeds. Startup errors and supervised branch errors are returned;
the application layer adds no retry, restart, or shutdown-drain protocol.

Normal startup leaves fixed connections summarized unless `--fixed` selects the
legacy compatibility projection in which they also load as full nodes. The
retired AudioIngress database option and migration remain absent, and existing
legacy data remains offline and untouched.

Fresh resolver builds use compatible conversation-stack updates. Telegram
serializes one `Session` owner per actor key, admits later messages at yielded
stepped-turn boundaries, and settles provider waits before deadline cleanup.
Resolver selection, rebuilt executable, deployment, and live validation are
separate.

The session stack records normalized provider submissions for exact Context
View and Structured Material inspection. Primary Codex generation retains
durable native thread affinity only for append-only Chatend changes and submits
the journal delta after a successful synchronization point. If earlier
provider-visible context is rewritten, the session abandons that continuation,
clears affinity, and starts a fresh outer round from the complete current
projection; logs identify the thread action and explicit reset reason.

One shared async mutex serializes application Kweb writers across general
orchestration, Telegram root reconciliation, Telegram wakeups, self-time, and
history ingress. Independent transport and read-only work remains concurrent.
Administrator mutations are durably admitted to their SQLite command lane
before its supervised runtime waits for Kweb's global writer ordering.

The input domain is the CLI parser's accepted finite argument sequence plus the
configured UTF-8 paths, listener address, environment, vault contents, and
persistent stores. Application-owned startup work is linear in argument and path
bytes, performs one command dispatch, attempts at most one public-listener bind,
visits a fixed set of runtime paths, constructs each capability once, and admits
five supervised futures. Additional work and memory scale under each capability's
contract with persisted records, media bytes, prompt bytes, and provider calls.
Application-owned peak memory is linear in retained argument, path, and secret
bytes plus the fixed capability graph; opened services own their caches and
persistent-state memory.

The operation may prompt on the controlling terminal; read and write configured
files and SQLite stores; bind and serve the public listener; and cause provider,
Telegram, and other network I/O through composed capabilities. The application
layer adds no provider attempt, retry, cancellation, or timeout beyond those
capabilities' contracts and cannot promise terminal, filesystem, database,
network, provider, or process-lifetime completion. Its reproducible ordering and
work canary is the release-profile test suite on one x86_64 Linux core with Rust
1.97: an occupied ephemeral loopback listener must prevent creation of every
configured data path, and the managed-root fixture verifies one-time capability
wiring at realistic path counts. These are deterministic work and ordering
checks, not an end-to-end latency claim.

### `maintenance_guard`

```rust
pub async fn maintenance_guard(
    bind: &str,
    purpose: &str,
) -> anyhow::Result<tokio::net::TcpListener>
```

`bind` must be an address accepted by Tokio's TCP listener binding operation.
`purpose` is arbitrary UTF-8 diagnostic text. The function makes exactly one
bind attempt. On success it returns the bound listener, and the caller controls
how long the process guard remains held. On failure it preserves the bind error
and adds `binding maintenance lock {bind}; stop the running Kennedy server
before {purpose}` as context. It does not open application persistence or
perform maintenance itself.

Work is linear in the address bytes parsed by Tokio and, on error, the diagnostic
bytes, with one socket creation and bind attempt and constant application-owned
allocation apart from the returned listener or error. It performs no traffic,
disk I/O, subprocess work, retries, timeout, or internal synchronization.
Concurrent exclusion is the operating system's listener-binding behavior. The
reproducible canary is an occupied ephemeral IPv4 loopback address on one
x86_64 Linux core with Rust 1.97; the attempt must complete with one contextual
error and no application data-path creation. Operating-system scheduling and
socket latency are outside an application wall-clock guarantee.