docs: consolidate design documentation and standardize crate English

This commit is contained in:
2026-10-12 14:58:00 +09:00
parent a633a53274
commit 4efb0ace1f
404 changed files with 4556 additions and 11654 deletions
+9 -27
View File
@@ -1,31 +1,13 @@
# protocol
## Role
`protocol` defines input, control, event, and public history types shared by Workers
and clients. It does not own transport, stored-log replay, or rendering. It separates
live state from committed history so clients can reconnect without depending on storage formats.
`protocol` defines the JSONL message boundary between Worker clients and Worker servers.
## Design entry points
## Boundaries
Owns:
- transport-neutral method/event/result types
- request/reply and broadcast event shapes
- protocol error categories shared by clients and servers
Does not own:
- Unix socket implementation details (`client`, `worker`)
- TUI rendering (`tui`)
- Engine history semantics (`agen`)
- durable storage (`session-store`, `session-store` worker metadata)
## Design notes
The exact enum variants are code authority. The README should describe the boundary, not duplicate every message shape.
Protocol events can inform UI and orchestration, but durable state changes still need to flow through Worker/session/metadata records.
## See also
- [`../../docs/design/worker-session-state.md`](../../docs/design/worker-session-state.md)
- [`../../docs/design/context-history.md`](../../docs/design/context-history.md)
- [`Method`] / [`Event`]: input acceptance versus live updates and history commits
- [`WorkerStateSnapshot`]: controller state versus Runtime catalog state
- [`SessionSnapshot`]: public representation of committed history
- [`subscription`]: ordering of snapshots and subsequent events
- [`invocation`]: validation of typed Feature input
+18
View File
@@ -1,3 +1,5 @@
#![doc = include_str!("../README.md")]
pub mod identity;
pub mod invocation;
#[cfg(feature = "stream")]
@@ -211,6 +213,10 @@ pub struct WorkerStateSnapshot {
pub state: WorkerState,
}
/// Handles current controller state; input admission is not inferred from past history.
///
/// Distinguishes Run from maintenance. The Runtime catalog's `Stopped` state persists
/// after shutdown and is not part of this controller snapshot.
impl WorkerStateSnapshot {
pub fn initial() -> Self {
Self {
@@ -445,6 +451,11 @@ pub enum WorkerEvent {
},
}
/// Separates child reports into control handling and model-facing notifications.
///
/// Scope registration updates are control-only and do not wake the parent's model.
/// Messages may arrive out of order; child notifications prompt state checks,
/// not proof of completed artifacts or validation.
impl WorkerEvent {
/// Whether this event should become an agent-visible notification/history item.
///
@@ -732,6 +743,13 @@ impl Segment {
}
}
/// Treats input acceptance and model-history inclusion as separate boundaries.
///
/// Submit/Notify receipts do not imply execution success; the corresponding Event
/// reports committed history. Human Submit requests use a waiting FIFO, while agents
/// use SubmitIfIdle only when Idle, never implicitly scheduling the next Run.
/// Pause/Resume suspend and resume a Run independently of new Submit acceptance;
/// Resume does not create a new user message.
impl Method {
/// Convenience: a `Submit` carrying a single `Segment::Text`.
/// Used by dumb clients, inter-Worker tools, and tests that only have
+15 -5
View File
@@ -1,9 +1,19 @@
//! Shared subscription-multiplexer wire contract.
//! Transport contract for multiple subscriptions over one connection.
//!
//! This protocol is distinct from the single-Worker [`crate::Method`] / [`crate::Event`]
//! protocol. A connection carries many independently managed subscriptions. The
//! connection endpoint owns authorization and maps the typed selectors below to
//! visible resources; clients cannot provide Workspace scope as selector input.
//! Manages subscriptions separately from a single Worker's [`crate::Method`] and
//! [`crate::Event`]. The endpoint owns authorization and selector resolution;
//! it does not accept Workspace scope from clients. Each subscription snapshot
//! anchors subsequent events; reconnecting replaces public state.
//!
//! Worker snapshots use public DTOs, not stored logs, keeping storage replay rules
//! out of clients. Committed history and uncommitted output stay separate;
//! subsequent history-commit events are matched by entry ID. Reasoning and internal
//! extension payloads are not exposed in conversation views.
//!
//! Input acceptance, stream deltas, and history commits are distinct boundaries;
//! live notifications alone do not establish durable state or completed results.
//! Turn boundaries also differ from individual generation requests. Transport
//! retries before streaming are retry notifications for the same generation request.
use std::collections::HashSet;
use std::fmt;
+15 -4
View File
@@ -173,11 +173,13 @@ pub fn generated_protocol_types() -> String {
normalize_typescript(output)
}
/// Render the strict runtime validator paired with the generated declarations.
/// Generates the Browser receive validator paired with TypeScript declarations.
///
/// `schemars` projects the reachable Serde shape from [`SubscriptionFrame`]. The
/// normalization closes every object and expands flattened enum payloads before
/// embedding that schema into the dependency-free Browser validator template.
/// Normalizes schemas reachable from [`SubscriptionFrame`] to Rust's actual wire shape.
/// Corrects required/nullable fields and integer bounds rather than adopting Serde's
/// decode-time omission rules as the receive contract. Expands common flattened-enum
/// fields into each variant before closing objects, then embeds the schema in a
/// validator template that rejects unknown fields.
pub fn generated_protocol_validator() -> String {
let mut schema = serde_json::to_value(schemars::schema_for!(SubscriptionFrame))
.expect("SubscriptionFrame schema must serialize");
@@ -365,6 +367,8 @@ fn close_object_shapes(schema: &mut Value) {
}
}
/// Makes schemas with `default: null` accept null in their types as well.
/// A null default with a string-only or similar type would reject null sent by Rust.
fn normalize_null_default(schema: &mut Map<String, Value>) {
if schema.get("default") != Some(&Value::Null) || schema.contains_key("anyOf") {
return;
@@ -386,6 +390,10 @@ fn normalize_null_default(schema: &mut Map<String, Value>) {
}
}
/// Limits JSON integers to the intersection of Rust's type range and JavaScript's
/// safe-integer range for TypeScript `number`. Never relaxes explicit bounds;
/// rejects unknown formats during generation rather than emitting integer types
/// with unknown ranges as if they could be validated.
fn normalize_integer_format(schema: &mut Map<String, Value>) {
let is_integer = match schema.get("type") {
Some(Value::String(value)) => value == "integer",
@@ -426,6 +434,9 @@ fn tighten_numeric_bound(
);
}
/// Serde decode-time defaults do not imply omitted fields on the wire.
/// Restores fields with schema defaults to required to match the serialized shape.
/// Does not fill missing fields with defaults in the Browser.
fn require_serialized_defaults(schema: &mut Map<String, Value>) {
if schema.get("type").and_then(Value::as_str) != Some("object") {
return;