1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//! The registry, deliverable, manager, pairing and delegation RPC methods
//! (#6288 slice 5).
//!
//! Why one module for five families: they are the daemon's RECORD-KEEPING
//! surface — projects and their deliverables, the L3 rollup over both, the bot
//! binding, and the delegation ledger. They share one property that matters
//! here: every one of them is a plain request/response route over daemon-owned
//! state, so all of them move onto the socket by the same mechanism and none of
//! them needs the streaming seam. Splitting them across five top-level modules
//! would put five `register` lines in `socket.rs` for one slice.
//!
//! What: [`register`] mounts all of them, and [`METHODS`] pins the names. The
//! per-family registrations live in the submodules, and the transport-neutral
//! bodies live beside their HTTP handlers — except where the handler's file sits
//! on a frozen SLOC budget, which is why the legacy `/projects*` and `/pair/*`
//! bodies live in [`projects`] and [`pairing`] instead of in `api.rs`.
//!
//! Nothing in this module or its submodules names an HTTP type. The one error
//! enum that crosses both transports — [`DaemonError`] — owns its own
//! `From<…> for RpcError`, derived from the same status table the HTTP
//! transport reads, so a code and a status cannot drift apart.
//!
//! ## Method → route
//!
//! | Method | Route |
//! |---|---|
//! | `mpm.projects.list` | `GET /projects` |
//! | `mpm.projects.register` | `POST /projects` |
//! | `mpm.projects.current` | `GET /projects/current?path=` |
//! | `mpm.projects.discover` | `GET /projects/discover` |
//! | `mpm.projects.registry.list` | `GET /api/v1/projects` |
//! | `mpm.projects.registry.register` | `POST /api/v1/projects` |
//! | `mpm.projects.registry.get` | `GET /api/v1/projects/{name}` |
//! | `mpm.projects.registry.patch` | `PATCH /api/v1/projects/{name}` |
//! | `mpm.projects.status` | `GET /api/v1/projects/{name}/status` |
//! | `mpm.deliverables.create` | `POST /api/v1/projects/{name}/deliverables` |
//! | `mpm.deliverables.list` | `GET /api/v1/projects/{name}/deliverables` |
//! | `mpm.deliverables.get` | `GET /api/v1/projects/{name}/deliverables/{id}` |
//! | `mpm.deliverables.patch` | `PATCH /api/v1/projects/{name}/deliverables/{id}` |
//! | `mpm.milestones.create` | `POST /api/v1/projects/{name}/milestones` |
//! | `mpm.milestones.list` | `GET /api/v1/projects/{name}/milestones` |
//! | `mpm.milestones.get` | `GET /api/v1/projects/{name}/milestones/{id}` |
//! | `mpm.milestones.patch` | `PATCH /api/v1/projects/{name}/milestones/{id}` |
//! | `mpm.manager.version` | `GET /api/v1/manager/version` |
//! | `mpm.manager.status` | `GET /api/v1/manager/status` |
//! | `mpm.manager.digest` | `GET /api/v1/manager/digest?scope=` |
//! | `mpm.manager.chat` | `POST /api/v1/manager/chat` |
//! | `mpm.manager.route_task` | `POST /api/v1/manager/route-task` |
//! | `mpm.manager.act` | `POST /api/v1/manager/act` |
//! | `mpm.pair.request` | `POST /pair/request` |
//! | `mpm.pair.confirm` | `POST /pair/confirm` |
//! | `mpm.pair.status` | `GET /pair/status` |
//! | `mpm.pair.reset` | `POST /pair/reset` |
//! | `mpm.delegation.shared_tree_dispatch` | `POST /api/v1/sessions/{id}/delegations/shared-tree-dispatch` |
//! | `mpm.delegation.granted_worktree` | `POST /api/v1/sessions/{id}/delegations/granted-worktree` |
//! | `mpm.delegation.list` | `GET /api/v1/delegations?cwd=` (step 2a) |
//! | `mpm.delegation.repair` | `POST /api/v1/delegations/{agent_id}/repair` (step 2a) |
//! | `mpm.delegation.repair_by_id` | `POST /api/v1/delegations/by-id/{delegation_id}/repair` (step 2a) |
//!
//! **`mpm.manager.digest` reports failure in its RESULT, not an error frame.**
//! Where HTTP answers `503` (no inference provider) or `502` (the provider call
//! failed), the socket answers a normal result carrying the same complete
//! `DigestResponse` — deterministic narrative plus the full rollup — with
//! `error: Some("inference_unavailable")` or `Some("inference_failed")`. A
//! caller that reads only the narrative will silently treat a degraded digest as
//! an LLM-authored one, so **check `error` before trusting `narrative`**;
//! `generated_by` says the same thing a second way. The three genuinely empty
//! refusals — malformed scope, unknown project, store read failed — ARE error
//! frames. See [`manager`]'s module doc for why the degrade legs cannot be.
//!
//! **No peer-bus method is served here (#6288 slice A).** Slice 5 mounted
//! `mpm.bus.register`, `mpm.bus.deregister`, `mpm.bus.list` and
//! `mpm.bus.publish` on this router. The 2026-09-05 owner ruling makes
//! trusty-console the host of the only event bus, so mpm publishes to console
//! through the `trusty-common` PushClient (#6849) instead of serving a bus of
//! its own over the socket. The four names are gone from [`METHODS`] and a call
//! to any of them answers `method_not_found`. `PeerBus` itself — the registry,
//! the envelope, the fail-closed publish sequencing — is untouched and still
//! reachable over HTTP; only the RPC mounting went away.
//!
//! ## Path and query parameters become named fields
//!
//! A JSON-RPC call has no path and no query string, so `{name}`, `{id}` and
//! `?status=` / `?scope=` / `?path=` all arrive as named
//! parameter fields. Where a route takes a path segment AND a body, the params
//! struct `#[serde(flatten)]`s the body around the segment field, so the wire is
//! the HTTP body plus one key rather than a nested object.
//!
//! Test: `registry/tests.rs` — one parity case per route.
//!
//! [`DaemonError`]: crate::daemon::error::DaemonError
//!
//! [`register`]: crate::daemon::rpc::registry::register
//! [`METHODS`]: crate::daemon::rpc::registry::METHODS
//! [`projects`]: crate::daemon::rpc::registry::projects
//! [`pairing`]: crate::daemon::rpc::registry::pairing
//! [`manager`]: crate::daemon::rpc::registry::manager
use Arc;
use Deserialize;
use RpcRouter;
use crateDaemonState;
/// Every method name this module registers, sorted.
///
/// Why pinned here: the slice-7 client swap and trusty-console will dial these
/// names by literal, with no compile-time link to the registrations. A rename
/// then becomes a failing assertion rather than a consumer that silently
/// reports `method_not_found`.
/// Test: `rpc_router_registers_every_documented_method`.
pub const METHODS: & = &;
/// A method that takes no arguments, tolerating `null` and a stray object.
///
/// Why a local copy rather than a re-export of [`crate::daemon::rpc::core`]'s:
/// that one is `pub`, so this could import it — but importing a sibling FAMILY's
/// type would make slice 2's file a dependency of slice 5's for a six-line
/// struct, and the two slices are meant to be independently reviewable. The
/// consolidation belongs in `trusty-common` alongside `RpcRouter`, where every
/// daemon's no-argument methods can share one.
/// Test: `rpc_projects_list_answers_with_no_params`.
;
/// Mount every method in this module's table onto `router`.
///
/// Test: `rpc_router_registers_every_documented_method`.