dsh-plugin-dev-kb 1.0.9 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.en.md +14 -8
  3. package/README.md +14 -8
  4. package/docs/banner.svg +25 -0
  5. package/kb/INDEX.md +8 -2
  6. package/kb/README.md +4 -4
  7. package/kb/extra/AGENTS.md +3 -3
  8. package/kb/extra/cookbook/adding-a-remote-api.md +197 -0
  9. package/kb/extra/cookbook/adding-a-remote-api.zh.md +197 -0
  10. package/kb/extra/cookbook/adding-a-session-format-version.md +109 -0
  11. package/kb/extra/cookbook/adding-a-session-format-version.zh.md +109 -0
  12. package/kb/extra/cookbook/adding-a-vendored-package.md +1 -1
  13. package/kb/extra/cookbook/adding-a-vendored-package.zh.md +1 -1
  14. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.md +1 -1
  15. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.zh.md +1 -1
  16. package/kb/extra/deepseek-llm-api-wire-extensions.md +19 -15
  17. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +19 -15
  18. package/kb/extra/development.md +13 -3
  19. package/kb/extra/development.zh.md +13 -3
  20. package/kb/extra/event-producer-consumer.md +49 -46
  21. package/kb/extra/event-producer-consumer.zh.md +52 -49
  22. package/kb/extra/i18n/README.md +2 -1
  23. package/kb/extra/i18n/README.zh.md +3 -2
  24. package/kb/extra/i18n/style-samples.md +2 -2
  25. package/kb/extra/i18n/translation-prompt.md +1 -1
  26. package/kb/extra/module-graph.md +493 -1002
  27. package/kb/extra/module-graph.zh.md +495 -1004
  28. package/kb/extra/rescope.md +1 -1
  29. package/kb/extra/rescope.zh.md +1 -1
  30. package/kb/extra/session-format-status.md +47 -0
  31. package/kb/extra/session-format-status.zh.md +47 -0
  32. package/kb/extra/subsystems/agent-team.md +3 -2
  33. package/kb/extra/subsystems/agent-team.zh.md +3 -2
  34. package/kb/extra/subsystems/attachment.md +157 -4
  35. package/kb/extra/subsystems/attachment.zh.md +157 -4
  36. package/kb/extra/subsystems/feedback.md +164 -30
  37. package/kb/extra/subsystems/feedback.zh.md +164 -30
  38. package/kb/extra/testing.md +9 -4
  39. package/kb/extra/testing.zh.md +9 -4
  40. package/kb/extra/web-styling.md +5 -0
  41. package/kb/extra/web-styling.zh.md +5 -0
  42. package/kb/meta/search-index.json +223 -151
  43. package/kb/meta/site-pages.txt +187 -181
  44. package/kb/meta/source.json +5 -5
  45. package/kb/meta/topics.md +5 -5
  46. package/kb/site/develop/basic/publish.md +1 -1
  47. package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +3 -2
  48. package/kb/site/develop/practice/llm-adapter.md +4 -3
  49. package/kb/site/en/develop/basic/publish.md +1 -1
  50. package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +3 -2
  51. package/kb/site/en/develop/practice/llm-adapter.md +4 -3
  52. package/kb/site/en/guide/network-proxy.md +87 -0
  53. package/kb/site/en/guide/providers.md +70 -17
  54. package/kb/site/en/guide/python-sdk.md +19 -3
  55. package/kb/site/en/guide/schedule.md +2 -0
  56. package/kb/site/en/reference/agent-lifecycle.md +17 -8
  57. package/kb/site/en/reference/api-gateway.md +2 -2
  58. package/kb/site/en/reference/capability-seams.md +24 -10
  59. package/kb/site/en/reference/config-catalog.md +322 -264
  60. package/kb/site/en/reference/cookbook/adding-a-package.md +1 -2
  61. package/kb/site/en/reference/cookbook/adding-a-settings-card.md +10 -8
  62. package/kb/site/en/reference/cookbook/adding-a-tool.md +1 -1
  63. package/kb/site/en/reference/cookbook/extension-cookbook.md +16 -13
  64. package/kb/site/en/reference/index.md +26 -9
  65. package/kb/site/en/reference/persistence-catalog.md +189 -95
  66. package/kb/site/en/reference/subsystems/approval.md +1 -1
  67. package/kb/site/en/reference/subsystems/client-modules.md +9 -0
  68. package/kb/site/en/reference/subsystems/client-resources.md +94 -0
  69. package/kb/site/en/reference/subsystems/code-runtime.md +7 -3
  70. package/kb/site/en/reference/subsystems/commands.md +25 -16
  71. package/kb/site/en/reference/subsystems/compaction.md +10 -10
  72. package/kb/site/en/reference/subsystems/conversation.md +11 -4
  73. package/kb/site/en/reference/subsystems/core.md +173 -29
  74. package/kb/site/en/reference/subsystems/credentials.md +5 -4
  75. package/kb/site/en/reference/subsystems/filesystem.md +15 -0
  76. package/kb/site/en/reference/subsystems/goal.md +38 -2
  77. package/kb/site/en/reference/subsystems/index.md +3 -1
  78. package/kb/site/en/reference/subsystems/invariants.md +1 -1
  79. package/kb/site/en/reference/subsystems/llm-streaming.md +43 -12
  80. package/kb/site/en/reference/subsystems/lsp.md +1 -1
  81. package/kb/site/en/reference/subsystems/permission-presets.md +5 -5
  82. package/kb/site/en/reference/subsystems/persistence.md +211 -199
  83. package/kb/site/en/reference/subsystems/plan.md +3 -3
  84. package/kb/site/en/reference/subsystems/sandbox.md +2 -0
  85. package/kb/site/en/reference/subsystems/schedule.md +9 -3
  86. package/kb/site/en/reference/subsystems/scope.md +1 -1
  87. package/kb/site/en/reference/subsystems/session-projection.md +50 -24
  88. package/kb/site/en/reference/subsystems/session-query.md +19 -13
  89. package/kb/site/en/reference/subsystems/session-reference.md +29 -1
  90. package/kb/site/en/reference/subsystems/session-telemetry.md +27 -10
  91. package/kb/site/en/reference/subsystems/session-title.md +6 -6
  92. package/kb/site/en/reference/subsystems/session.md +208 -103
  93. package/kb/site/en/reference/subsystems/settings.md +30 -12
  94. package/kb/site/en/reference/subsystems/shell.md +9 -6
  95. package/kb/site/en/reference/subsystems/sidebar-right.md +151 -0
  96. package/kb/site/en/reference/subsystems/skills.md +1 -1
  97. package/kb/site/en/reference/subsystems/slots.md +41 -32
  98. package/kb/site/en/reference/subsystems/spill.md +13 -6
  99. package/kb/site/en/reference/subsystems/storage.md +28 -5
  100. package/kb/site/en/reference/subsystems/subagent.md +58 -105
  101. package/kb/site/en/reference/subsystems/subprocess.md +25 -26
  102. package/kb/site/en/reference/subsystems/system-prompt.md +18 -3
  103. package/kb/site/en/reference/subsystems/token-meter.md +4 -3
  104. package/kb/site/en/reference/subsystems/tools.md +5 -5
  105. package/kb/site/en/reference/subsystems/typert.md +18 -18
  106. package/kb/site/en/reference/subsystems/web-client.md +1 -1
  107. package/kb/site/en/reference/subsystems/workspace.md +88 -9
  108. package/kb/site/en/reference/tool-catalog.md +56 -66
  109. package/kb/site/en/reference/tool-execution-pipeline.md +2 -2
  110. package/kb/site/guide/network-proxy.md +87 -0
  111. package/kb/site/guide/providers.md +70 -17
  112. package/kb/site/guide/python-sdk.md +19 -3
  113. package/kb/site/guide/schedule.md +2 -0
  114. package/kb/site/reference/agent-lifecycle.md +17 -8
  115. package/kb/site/reference/api-gateway.md +2 -2
  116. package/kb/site/reference/capability-seams.md +24 -10
  117. package/kb/site/reference/config-catalog.md +321 -263
  118. package/kb/site/reference/cookbook/adding-a-package.md +1 -2
  119. package/kb/site/reference/cookbook/adding-a-settings-card.md +10 -8
  120. package/kb/site/reference/cookbook/adding-a-tool.md +1 -1
  121. package/kb/site/reference/cookbook/extension-cookbook.md +16 -13
  122. package/kb/site/reference/index.md +26 -9
  123. package/kb/site/reference/persistence-catalog.md +190 -96
  124. package/kb/site/reference/subsystems/approval.md +1 -1
  125. package/kb/site/reference/subsystems/client-modules.md +9 -0
  126. package/kb/site/reference/subsystems/client-resources.md +94 -0
  127. package/kb/site/reference/subsystems/code-runtime.md +7 -3
  128. package/kb/site/reference/subsystems/commands.md +25 -16
  129. package/kb/site/reference/subsystems/compaction.md +10 -10
  130. package/kb/site/reference/subsystems/conversation.md +11 -4
  131. package/kb/site/reference/subsystems/core.md +173 -29
  132. package/kb/site/reference/subsystems/credentials.md +5 -4
  133. package/kb/site/reference/subsystems/filesystem.md +15 -0
  134. package/kb/site/reference/subsystems/goal.md +38 -2
  135. package/kb/site/reference/subsystems/index.md +14 -12
  136. package/kb/site/reference/subsystems/invariants.md +1 -1
  137. package/kb/site/reference/subsystems/llm-streaming.md +43 -12
  138. package/kb/site/reference/subsystems/lsp.md +1 -1
  139. package/kb/site/reference/subsystems/permission-presets.md +5 -5
  140. package/kb/site/reference/subsystems/persistence.md +210 -198
  141. package/kb/site/reference/subsystems/plan.md +3 -3
  142. package/kb/site/reference/subsystems/schedule.md +9 -3
  143. package/kb/site/reference/subsystems/scope.md +1 -1
  144. package/kb/site/reference/subsystems/session-projection.md +50 -24
  145. package/kb/site/reference/subsystems/session-query.md +19 -13
  146. package/kb/site/reference/subsystems/session-reference.md +29 -1
  147. package/kb/site/reference/subsystems/session-telemetry.md +27 -10
  148. package/kb/site/reference/subsystems/session-title.md +6 -6
  149. package/kb/site/reference/subsystems/session.md +208 -103
  150. package/kb/site/reference/subsystems/settings.md +30 -12
  151. package/kb/site/reference/subsystems/shell.md +9 -6
  152. package/kb/site/reference/subsystems/sidebar-right.md +151 -0
  153. package/kb/site/reference/subsystems/skills.md +1 -1
  154. package/kb/site/reference/subsystems/slots.md +41 -32
  155. package/kb/site/reference/subsystems/spill.md +13 -6
  156. package/kb/site/reference/subsystems/storage.md +28 -5
  157. package/kb/site/reference/subsystems/subagent.md +58 -105
  158. package/kb/site/reference/subsystems/subprocess.md +25 -26
  159. package/kb/site/reference/subsystems/system-prompt.md +18 -3
  160. package/kb/site/reference/subsystems/token-meter.md +4 -3
  161. package/kb/site/reference/subsystems/tools.md +5 -5
  162. package/kb/site/reference/subsystems/typert.md +18 -18
  163. package/kb/site/reference/subsystems/web-client.md +1 -1
  164. package/kb/site/reference/subsystems/workspace.md +88 -9
  165. package/kb/site/reference/tool-catalog.md +55 -65
  166. package/kb/site/reference/tool-execution-pipeline.md +2 -2
  167. package/lib/index.js +25 -44
  168. package/package.json +3 -2
  169. package/skills/dsh-plugin-dev-kb.md +4 -4
@@ -2,7 +2,7 @@
2
2
 
3
3
  English | [中文](feedback.zh.md)
4
4
 
5
- [`@deepseek-ai/dsh-message-feedback`](../../packages/feedback/message-feedback) owns editable feedback for individual assistant messages. It is deliberately separate from the immutable Session-level `feedback/record` event: message feedback is a local storage-domain sidecar, not Session-log content or a projection, and it performs no telemetry handoff.
5
+ [`@deepseek-ai/dsh-message-feedback`](../../packages/feedback/message-feedback) owns editable feedback for individual assistant messages. The canonical Session log stores `feedback/message-put` and `feedback/message-delete`; the immutable Session-level remark remains `feedback/record`, owned by [`@deepseek-ai/dsh-command-feedback`](../../packages/feedback/command-feedback) together with the `FeedbackCategory` taxonomy both kinds of feedback file under. All three are log-only events that never enter model context.
6
6
 
7
7
  Source: [`packages/feedback/message-feedback/src/types.ts`](../../packages/feedback/message-feedback/src/types.ts)
8
8
 
@@ -27,6 +27,8 @@ interface MessageFeedbackItem {
27
27
  readonly rating: MessageFeedbackRating
28
28
  /** Optional explanation, preserved verbatim after validation. */
29
29
  readonly note?: string
30
+ /** Category the human filed a negative judgment under. */
31
+ readonly category?: FeedbackCategory
30
32
  /** Equality-only token replaced by every material create or update. */
31
33
  readonly version: MessageFeedbackVersion
32
34
  /** Host-assigned creation time in Unix epoch milliseconds. */
@@ -36,10 +38,30 @@ interface MessageFeedbackItem {
36
38
  }
37
39
  ```
38
40
 
41
+ ```ts type-equiv
42
+ /** A material creation or edit, retaining its complete current value. */
43
+ interface MessageFeedbackPut {
44
+ /** Owning Session; inherited feedback in a fork belongs to its parent. */
45
+ readonly sessionId: SessionId
46
+ /** Value after this mutation, including the original creation time. */
47
+ readonly item: MessageFeedbackItem
48
+ }
49
+ ```
50
+
51
+ ```ts type-equiv
52
+ /** A material deletion of one current feedback item. */
53
+ interface MessageFeedbackDelete {
54
+ /** Session that owns the deleted feedback. */
55
+ readonly sessionId: SessionId
56
+ /** Message whose feedback was removed. */
57
+ readonly messageId: MessageId
58
+ }
59
+ ```
60
+
39
61
  ```ts type-equiv
40
62
  /** Read all message feedback belonging to one persisted Session lifecycle. */
41
63
  interface MessageFeedbackListRequest {
42
- /** Persisted Session whose sidecar should be read. */
64
+ /** Session whose feedback events should be read. */
43
65
  readonly sessionId: SessionId
44
66
  }
45
67
  ```
@@ -63,6 +85,8 @@ interface MessageFeedbackPutRequest {
63
85
  readonly rating: MessageFeedbackRating
64
86
  /** Optional non-blank explanation. */
65
87
  readonly note?: string
88
+ /** Optional category; absent keeps the item uncategorized. */
89
+ readonly category?: FeedbackCategory
66
90
  /** Observed item version, or `null` to require that no item exists. */
67
91
  readonly ifVersion: MessageFeedbackVersion | null
68
92
  }
@@ -71,7 +95,7 @@ interface MessageFeedbackPutRequest {
71
95
  ```ts type-equiv
72
96
  /** Delete feedback for one message after observing its current version. */
73
97
  interface MessageFeedbackDeleteRequest {
74
- /** Persisted Session that owns the sidecar. */
98
+ /** Session that owns the feedback. */
75
99
  readonly sessionId: SessionId
76
100
  /** Message whose feedback should be absent after this operation. */
77
101
  readonly messageId: MessageId
@@ -183,43 +207,112 @@ type MessageFeedbackDeleteResult =
183
207
  | MessageFeedbackRejected<MessageFeedbackSessionNotFound | MessageFeedbackVersionConflict>
184
208
  ```
185
209
 
210
+ ## Session feedback types
211
+
212
+ Source: [`packages/feedback/command-feedback/src/types.ts`](../../packages/feedback/command-feedback/src/types.ts)
213
+
214
+ ```ts type-equiv
215
+ /** One of the fixed feedback categories; the ids are durable log vocabulary. */
216
+ type FeedbackCategory =
217
+ | 'task-result'
218
+ | 'instruction-following'
219
+ | 'product-interaction'
220
+ | 'service-stability'
221
+ | 'resource-cost'
222
+ | 'security-privacy-permission'
223
+ | 'other'
224
+ ```
225
+
226
+ ```ts type-equiv
227
+ /**
228
+ * One recorded human remark about a Session. Both members are optional: a
229
+ * submission with neither still records that the human asked for the
230
+ * Session to be reviewed, which is what authorizes log delivery.
231
+ */
232
+ interface FeedbackRecord {
233
+ /** Free-text remark with surrounding whitespace removed; never empty when present. */
234
+ readonly text?: string
235
+ /** Category the human filed the remark under. */
236
+ readonly category?: FeedbackCategory
237
+ }
238
+ ```
239
+
240
+ ```ts type-equiv
241
+ /** Record one Session-level remark through the Host Remote. */
242
+ interface SessionFeedbackRecordRequest {
243
+ /** Live Session the remark describes. */
244
+ readonly sessionId: SessionId
245
+ /** Free-text remark; blank text is recorded as absent. */
246
+ readonly text?: string
247
+ /** Category the human filed the remark under. */
248
+ readonly category?: FeedbackCategory
249
+ }
250
+ ```
251
+
252
+ ```ts type-equiv
253
+ /** Stable postcondition of a recorded remark. */
254
+ interface SessionFeedbackRecordValue {
255
+ /** The remark is appended to the Session log; flushing follows the Session's own schedule. */
256
+ readonly recorded: true
257
+ }
258
+ ```
259
+
260
+ ```ts type-equiv
261
+ /** No live Session carries the requested id. */
262
+ interface SessionFeedbackSessionNotFound {
263
+ readonly code: 'session-not-found'
264
+ readonly sessionId: SessionId
265
+ }
266
+ ```
267
+
268
+ ```ts type-equiv
269
+ /** Result returned by the `sessionFeedback.record` operation. */
270
+ type SessionFeedbackRecordResult =
271
+ | { readonly ok: true; readonly value: SessionFeedbackRecordValue }
272
+ | { readonly ok: false; readonly error: SessionFeedbackSessionNotFound }
273
+ ```
274
+
186
275
  ## Data and concurrency
187
276
 
188
- One Session sidecar row contains its header identity `{createdAt, cwd}` and feedback items keyed by `MessageId`. Each item carries a positive or negative rating, an optional note, Host-assigned `createdAt`/`updatedAt` timestamps, and its own opaque version. Versions are compared only for equality and only against the addressed message; callers do not order or synthesize them.
277
+ Current items are folded from canonical feedback events whose payload `sessionId` matches the owning Session. Each item carries a positive or negative rating, an optional note, an optional category, Host-assigned `createdAt`/`updatedAt` timestamps, and its own opaque version. Versions are compared only for equality and only against the addressed message; callers do not order or synthesize them.
189
278
 
190
- `put` uses strict optimistic concurrency: every request for an existing item must match its current `ifVersion`, including a no-op. A conflict returns the authoritative current item (or `null`), so a caller can reconcile a lost response or a concurrent edit without another read. Deleting an already absent item succeeds. A per-Session queue encloses inspection, read, conflict evaluation, and whole-row write, so these guarantees cover concurrent calls in one Host process.
279
+ `put` uses strict optimistic concurrency: every request for an existing item must match its current `ifVersion`, including a no-op (a put repeating the stored rating, note, and category). A conflict returns the authoritative current item (or `null`), so a caller can reconcile a lost response or a concurrent edit without another read. Deleting an already absent item succeeds. A per-Session queue serializes reads and mutations; cold mutations hold a persistence write handle across read, comparison, append, and flush. Matching no-ops append no event.
191
280
 
192
281
  ## Target and lifecycle authority
193
282
 
194
- `SessionPersistence.inspect()` supplies the target Session observation without publishing or resuming an Agent and without committing cold repair. A cold `listSnapshots()` preflight classifies definite absence; inspection failure for a catalogued Session propagates as infrastructure failure. `put` accepts only a non-empty, append-origin `assistant/message` with the requested `MessageId`; replacement-origin, usage-only empty, and non-assistant records are not feedback targets.
283
+ A live owner's in-memory log supplies the target Session observation directly; cold reads use a `SessionPersistence.open(id, 'read')` handle, while mutations use a write handle. Neither path constructs a Session or Agent. A `stat(id)` preflight classifies definite absence; a read failure for a Session `stat` confirmed propagates as infrastructure failure. `put` accepts only a non-empty, append-origin `assistant/message` with the requested `MessageId`; replacement-origin, usage-only empty, and non-assistant records are not feedback targets.
195
284
 
196
- The stored `{createdAt, cwd}` identity must match the inspected header. A mismatch is treated as absence: `list` returns no items, while `put` may replace the stale row with one bound to the current header identity. Forks use a new Session identity and receive no sidecar copy even when their seed contains the same messages.
285
+ Fork seeds can contain parent feedback events, but their payload retains the parent `sessionId`, so they do not become current feedback for the child. Deleting an item appends a tombstone; earlier ratings and notes remain in the log.
197
286
 
198
287
  ## Persistence and Remote contract
199
288
 
200
- The service stores whole Session rows in the `message_feedback` storage domain through `ctx.storageDomain`. Before `put` commits a row that references a target message, a matching live target passes through the canonical `ctx.sessions.flush` checkpoint; both live and cold paths are then physically read from sequence zero through `SessionPersistence.readFrom`. The resulting observation is revalidated before the sidecar write, so the durable target log always precedes its sidecar commit. `maxNoteBytes` is required and bounds note text by UTF-8 bytes; the Web Host composition sets `8192`. The package publishes the Host `messageFeedback.list`, `messageFeedback.put`, and `messageFeedback.delete` unary Remote contract through `TypertRemoteService` and `@Remote`; the generated Cordis API below is the method-level authority.
289
+ Successful message-feedback mutations await canonical persistence: live operations append through the owning Session and require a participating `ctx.sessions.flush` listener; cold operations append and flush through their write handle. Persistence failures propagate rather than reporting success. `maxNoteBytes` is required and bounds note text by UTF-8 bytes; the Web Host composition sets `8192`. The package publishes the Host `messageFeedback.list`, `messageFeedback.put`, and `messageFeedback.delete` unary Remote contract through `TypertRemoteService` and `@Remote`; `command-feedback` publishes `sessionFeedback.record` the same way for Session-level remarks on live Sessions. The generated Cordis API below is the method-level authority.
201
290
 
202
- Plugin disposal closes mutation admission, drains accepted per-Session queue work, and then closes the storage domain.
291
+ Plugin disposal closes operation admission and drains accepted per-Session queue work.
292
+
293
+ When explicitly enabled, [`session-log-deepseek`](../../packages/session/session-log-deepseek/README.md) carries feedback as part of the ordinary `dsh_session_log` suffix on subsequent eligible DeepSeek requests. Recording feedback does not trigger an LLM request or a separate `dsh_feedback` upload. For non-DeepSeek routes, the [OTel backend](../../packages/session/session-telemetry-otel/README.md) can release the canonical prefix through recorded feedback. The command acknowledgement confirms recording and identifies the Session and anonymous user; it reports neither telemetry policy nor delivery.
203
294
 
204
295
  ## Web surface
205
296
 
206
- [`@deepseek-ai/dsh-client-ui-message-feedback`](../../packages/client/ui-message-feedback) is the browser consumer. `@deepseek-ai/dsh-api-remotes` mounts the generated `messageFeedback` contribution, so the plugin calls `ctx.remote.messageFeedback` and never touches the transport.
297
+ [`@deepseek-ai/dsh-client-ui-message-feedback`](../../packages/client/ui-message-feedback) is the browser consumer. `@deepseek-ai/dsh-api-remotes` mounts the generated `messageFeedback` and `sessionFeedback` contributions, so the plugin calls `ctx.remote.messageFeedback` and `ctx.remote.sessionFeedback` and never touches the transport.
207
298
 
208
299
  The controls are the `feedback` entry (order 10) of the `conversation.chat.assistant-actions` list slot, which `ui-conversation` declares and renders inside the finalized assistant message's IconActions row. `AssistantMessageNode` carries the optional `messageId` from the `assistant/message` event. The field is absent on interruption-frozen partials, and the render site skips the slot when it is absent. The strip renders once per turn, on the closing assistant message: the Host accepts every append-origin step message as a target, but earlier steps of a multi-step turn render tool rows rather than a rateable body, so the UI exposes a narrower set than the Host contract allows.
209
300
 
210
301
  One `MessageFeedbackController` per Session backs every message control in that Session: a single `list` read seeds the whole transcript, deferred to first hover or focus rather than fired on mount. Each mutation sends the version that controller last observed as `ifVersion`; a `version-conflict` reply carries the authoritative item, so the controller reconciles from the reply instead of refetching. Mutations serialize per Session so a queued operation compares against the committed version. A `connection/reset` refreshes only Sessions already read.
211
302
 
303
+ Like records the bare positive judgment at once and shows the acknowledgement toast. Dislike opens the Session's feedback dialog, the `feedback-dialog` entry of `conversation.input.overlay`: the shared Modal card with seven category chips and a detail box. Submit puts a negative judgment carrying the chosen category and the trimmed description, or neither. The same dialog opens for the Session from a bare `/feedback` — a decoration `ui-commands` routes as an `action` — and then records through `sessionFeedback.record`; `/feedback <text>` keeps the Host command path. Clicking a recorded rating retracts it.
304
+
212
305
  ## Boundaries and limitations
213
306
 
214
- - The mutation queue is process-local. Storage-domain has no cross-process conditional write, so multiple Host writers to one storage root have no compare-and-swap or lost-update guarantee.
215
- - Session persistence has no durable deletion API. The service does not treat `session/disposed` or `api-session/removed` as deletion and therefore performs no fake cascade; orphan sidecar rows may remain after out-of-band log removal.
307
+ - The operation queue is process-local; cold writer exclusion relies on the selected persistence provider.
308
+ - Deletion removes the current item, not earlier note text from the append-only log or an already delivered suffix.
216
309
  - A request in the narrow interval after live detach but before the persistence catalog materializes the header can receive `session-not-found`; callers retry after retirement materialization.
217
- - Cold requests scan the complete Session snapshot catalog because persistence has no lookup-by-id metadata operation. One Session row also has no item-count or aggregate-byte cap; `maxNoteBytes` bounds only each note until a concrete consumer owns a row policy.
218
- - Header identity detects a reused id only when `{createdAt, cwd}` differs; a cloned log retaining the same header identity is indistinguishable by this contract.
310
+ - Cold requests read the complete log; the service has no item-count or aggregate-byte cap. `maxNoteBytes` bounds only each note.
219
311
  - The Host contract records no authenticated actor or audit identity and therefore assumes a trusted caller boundary.
220
312
  - The Web controls appear in the chat view only. The trajectory and waterfall views render no feedback entry even though their assistant nodes carry the same `messageId`.
221
- - The sidecar publishes no live frames, so a second tab's rating becomes visible on reconnect or on the next conflict reply rather than immediately.
222
- - The note editor does not pre-check `maxNoteBytes`; an oversized note fails on save with `note-too-large` rather than while typing.
313
+ - The Web controller does not consume feedback log events, so a second tab's rating becomes visible on reconnect or on the next conflict reply rather than immediately.
314
+ - The dialog does not pre-check `maxNoteBytes`; an oversized description for a message fails on submit with `note-too-large` rather than while typing. A Session remark has no size bound, as the `/feedback` command never had one.
315
+ - `sessionFeedback.record` serves live Sessions only and answers `session-not-found` otherwise; the dialog reports that failure when its Session retires while it is open.
223
316
 
224
317
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
225
318
 
@@ -233,34 +326,75 @@ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnp
233
326
 
234
327
  ### `ctx.messageFeedback` — `MessageFeedbackService`
235
328
 
236
- Storage-domain sidecar service. It inspects persisted Session history and never creates or resumes an Agent or Session.
329
+ Session-log service; cold operations never construct a Session or Agent.
237
330
 
238
331
  ```ts cordis-catalog
239
332
  /**
240
- * Read feedback belonging to the current persisted Session lifecycle.
241
- * A stale row from a reused Session id is invisible.
242
- * @param request - Session identity to inspect and list.
243
- * @returns current immutable items or `session-not-found`.
333
+ * Read current feedback from the canonical log.
334
+ * @param request - Session to inspect.
335
+ * @returns immutable items or a definite persistence miss.
244
336
  */
245
- @Remote('list') async list(request: MessageFeedbackListRequest): Promise<MessageFeedbackListResult>
337
+ @Remote('list') list(request: MessageFeedbackListRequest): Promise<MessageFeedbackListResult>
246
338
 
247
339
  /**
248
- * Create or replace feedback for one derived append-origin assistant
249
- * message. Every request must match the addressed item's current version;
250
- * a matching no-op returns the stored item without changing its revision.
251
- * @param request - target, desired value, and observed item version.
252
- * @returns the committed item or an explicit business failure.
340
+ * Create or replace feedback after checking its current version.
341
+ * Matching no-ops retain the version and append no event.
342
+ * @param request - Target, desired value, and observed item version.
343
+ * @returns the durable item or an explicit business failure.
253
344
  */
254
345
  @Remote('put') put(request: MessageFeedbackPutRequest): Promise<MessageFeedbackPutResult>
255
346
 
256
347
  /**
257
- * Delete one feedback item. Absence is successful regardless of the
258
- * supplied version; an existing item requires an exact version match.
348
+ * Delete one item after checking its version; absence succeeds without an event.
259
349
  * @param request - Session, message, and observed item version.
260
- * @returns the stable absent postcondition, or an explicit failure.
350
+ * @returns the stable absent postcondition or an explicit failure.
261
351
  */
262
352
  @Remote('delete') delete(request: MessageFeedbackDeleteRequest): Promise<MessageFeedbackDeleteResult>
263
353
  ```
264
354
 
355
+ Source: [`packages/feedback/message-feedback/src/index.ts`](../../packages/feedback/message-feedback/src/index.ts)
356
+
357
+ <a id="ctxsessionfeedback--sessionfeedbackservice"></a>
358
+
359
+ ### `ctx.sessionFeedback` — `SessionFeedbackService`
360
+
361
+ Host Remote through which a product surface records a Session-level remark.
362
+
363
+ ```ts cordis-catalog
364
+ /**
365
+ * Record one remark on a live Session.
366
+ * @param request - target Session plus the optional text and category.
367
+ * @returns the recorded postcondition, or `session-not-found` when no live
368
+ * Session carries the id.
369
+ */
370
+ @Remote('record') record(request: SessionFeedbackRecordRequest): Promise<SessionFeedbackRecordResult>
371
+ ```
372
+
373
+ Source: [`packages/feedback/command-feedback/src/index.ts`](../../packages/feedback/command-feedback/src/index.ts)
374
+
375
+ <a id="feedback-events"></a>
376
+
377
+ ### `feedback/*` events
378
+
379
+ <a id="feedbackcommitted--parallel"></a>
380
+
381
+ #### `feedback/committed` — parallel
382
+
383
+ Observe a durable cold feedback mutation without publishing a live Session. Observers run before write ownership is released and must not await another message-feedback operation for this Session. The payload is borrowed read-only; deep-clone it before transferring ownership (for example, to Session.fromRestore).
384
+
385
+ ```ts cordis-catalog
386
+ /**
387
+ * Observe a durable cold feedback mutation without publishing a live Session.
388
+ * Observers run before write ownership is released and must not await
389
+ * another message-feedback operation for this Session. The payload is borrowed
390
+ * read-only; deep-clone it before transferring ownership (for example, to Session.fromRestore).
391
+ * @param inspection - committed canonical prefix, including the feedback as its last event.
392
+ * @mode parallel
393
+ */
394
+ 'feedback/committed'(inspection: SessionInspection): void
395
+ ```
396
+
397
+ Types: [SessionInspection](persistence.md)
398
+
265
399
  Source: [`packages/feedback/message-feedback/src/index.ts`](../../packages/feedback/message-feedback/src/index.ts)
266
400
  <!-- END GENERATED cordis-surface -->
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](feedback.md) | 中文
4
4
 
5
- [`@deepseek-ai/dsh-message-feedback`](../../packages/feedback/message-feedback)拥有针对单条 assistant 消息的可编辑反馈。它刻意与不可变的 Session `feedback/record` 事件分离:message feedback 是本地 storage-domain 伴随记录(sidecar),不是 Session 日志内容或投影,也不执行遥测交接。
5
+ [`@deepseek-ai/dsh-message-feedback`](../../packages/feedback/message-feedback)拥有针对单条 assistant 消息的可编辑反馈。权威 Session 日志保存 `feedback/message-put` 和 `feedback/message-delete`;不可变的 Session 级备注仍使用 `feedback/record`,由 [`@deepseek-ai/dsh-command-feedback`](../../packages/feedback/command-feedback) 连同两种反馈共用的 `FeedbackCategory` 分类表一起拥有。三者都是仅写日志的事件,绝不进入模型上下文。
6
6
 
7
7
  来源:[`packages/feedback/message-feedback/src/types.ts`](../../packages/feedback/message-feedback/src/types.ts)
8
8
 
@@ -27,6 +27,8 @@ interface MessageFeedbackItem {
27
27
  readonly rating: MessageFeedbackRating
28
28
  /** Optional explanation, preserved verbatim after validation. */
29
29
  readonly note?: string
30
+ /** Category the human filed a negative judgment under. */
31
+ readonly category?: FeedbackCategory
30
32
  /** Equality-only token replaced by every material create or update. */
31
33
  readonly version: MessageFeedbackVersion
32
34
  /** Host-assigned creation time in Unix epoch milliseconds. */
@@ -36,10 +38,30 @@ interface MessageFeedbackItem {
36
38
  }
37
39
  ```
38
40
 
41
+ ```ts type-equiv
42
+ /** A material creation or edit, retaining its complete current value. */
43
+ interface MessageFeedbackPut {
44
+ /** Owning Session; inherited feedback in a fork belongs to its parent. */
45
+ readonly sessionId: SessionId
46
+ /** Value after this mutation, including the original creation time. */
47
+ readonly item: MessageFeedbackItem
48
+ }
49
+ ```
50
+
51
+ ```ts type-equiv
52
+ /** A material deletion of one current feedback item. */
53
+ interface MessageFeedbackDelete {
54
+ /** Session that owns the deleted feedback. */
55
+ readonly sessionId: SessionId
56
+ /** Message whose feedback was removed. */
57
+ readonly messageId: MessageId
58
+ }
59
+ ```
60
+
39
61
  ```ts type-equiv
40
62
  /** Read all message feedback belonging to one persisted Session lifecycle. */
41
63
  interface MessageFeedbackListRequest {
42
- /** Persisted Session whose sidecar should be read. */
64
+ /** Session whose feedback events should be read. */
43
65
  readonly sessionId: SessionId
44
66
  }
45
67
  ```
@@ -63,6 +85,8 @@ interface MessageFeedbackPutRequest {
63
85
  readonly rating: MessageFeedbackRating
64
86
  /** Optional non-blank explanation. */
65
87
  readonly note?: string
88
+ /** Optional category; absent keeps the item uncategorized. */
89
+ readonly category?: FeedbackCategory
66
90
  /** Observed item version, or `null` to require that no item exists. */
67
91
  readonly ifVersion: MessageFeedbackVersion | null
68
92
  }
@@ -71,7 +95,7 @@ interface MessageFeedbackPutRequest {
71
95
  ```ts type-equiv
72
96
  /** Delete feedback for one message after observing its current version. */
73
97
  interface MessageFeedbackDeleteRequest {
74
- /** Persisted Session that owns the sidecar. */
98
+ /** Session that owns the feedback. */
75
99
  readonly sessionId: SessionId
76
100
  /** Message whose feedback should be absent after this operation. */
77
101
  readonly messageId: MessageId
@@ -183,43 +207,112 @@ type MessageFeedbackDeleteResult =
183
207
  | MessageFeedbackRejected<MessageFeedbackSessionNotFound | MessageFeedbackVersionConflict>
184
208
  ```
185
209
 
210
+ ## Session 反馈类型
211
+
212
+ 来源:[`packages/feedback/command-feedback/src/types.ts`](../../packages/feedback/command-feedback/src/types.ts)
213
+
214
+ ```ts type-equiv
215
+ /** One of the fixed feedback categories; the ids are durable log vocabulary. */
216
+ type FeedbackCategory =
217
+ | 'task-result'
218
+ | 'instruction-following'
219
+ | 'product-interaction'
220
+ | 'service-stability'
221
+ | 'resource-cost'
222
+ | 'security-privacy-permission'
223
+ | 'other'
224
+ ```
225
+
226
+ ```ts type-equiv
227
+ /**
228
+ * One recorded human remark about a Session. Both members are optional: a
229
+ * submission with neither still records that the human asked for the
230
+ * Session to be reviewed, which is what authorizes log delivery.
231
+ */
232
+ interface FeedbackRecord {
233
+ /** Free-text remark with surrounding whitespace removed; never empty when present. */
234
+ readonly text?: string
235
+ /** Category the human filed the remark under. */
236
+ readonly category?: FeedbackCategory
237
+ }
238
+ ```
239
+
240
+ ```ts type-equiv
241
+ /** Record one Session-level remark through the Host Remote. */
242
+ interface SessionFeedbackRecordRequest {
243
+ /** Live Session the remark describes. */
244
+ readonly sessionId: SessionId
245
+ /** Free-text remark; blank text is recorded as absent. */
246
+ readonly text?: string
247
+ /** Category the human filed the remark under. */
248
+ readonly category?: FeedbackCategory
249
+ }
250
+ ```
251
+
252
+ ```ts type-equiv
253
+ /** Stable postcondition of a recorded remark. */
254
+ interface SessionFeedbackRecordValue {
255
+ /** The remark is appended to the Session log; flushing follows the Session's own schedule. */
256
+ readonly recorded: true
257
+ }
258
+ ```
259
+
260
+ ```ts type-equiv
261
+ /** No live Session carries the requested id. */
262
+ interface SessionFeedbackSessionNotFound {
263
+ readonly code: 'session-not-found'
264
+ readonly sessionId: SessionId
265
+ }
266
+ ```
267
+
268
+ ```ts type-equiv
269
+ /** Result returned by the `sessionFeedback.record` operation. */
270
+ type SessionFeedbackRecordResult =
271
+ | { readonly ok: true; readonly value: SessionFeedbackRecordValue }
272
+ | { readonly ok: false; readonly error: SessionFeedbackSessionNotFound }
273
+ ```
274
+
186
275
  ## 数据与并发
187
276
 
188
- 每个 Session 的一条伴随记录包含 header 身份 `{createdAt, cwd}` 和以 `MessageId` 为键的反馈条目。每个条目携带好评或差评、可选备注、Host 分配的 `createdAt`/`updatedAt` 时间戳及自己的 opaque version。version 只能用于相等比较,且只与目标消息比较;调用方不能排序或自行合成它。
277
+ 当前条目由 payload `sessionId` 与所属 Session 匹配的权威反馈事件归约得到。每个条目携带好评或差评、可选备注、可选分类、Host 分配的 `createdAt`/`updatedAt` 时间戳及自己的 opaque version。version 只能用于相等比较,且只与目标消息比较;调用方不能排序或自行合成它。
189
278
 
190
- `put` 采用严格乐观并发:已有条目的每次请求都必须匹配当前 `ifVersion`,即使请求不会改变目标值。冲突会返回权威当前条目(不存在时为 `null`),因此调用方无需额外读取,即可协调丢失响应或并发编辑。删除已经不存在的条目同样成功。按 Session 划分的队列覆盖检查、读取、冲突判断与整行写入,因此这些保证适用于单个 Host 进程中的并发调用。
279
+ `put` 采用严格乐观并发:已有条目的每次请求都必须匹配当前 `ifVersion`,即使请求不会改变目标值(重复已存评分、备注与分类的 put)。冲突会返回权威当前条目(不存在时为 `null`),因此调用方无需额外读取,即可协调丢失响应或并发编辑。删除已经不存在的条目同样成功。按 Session 划分的队列串行执行读取与变更;cold 变更在读取、比较、追加和 flush 期间持有持久化写句柄。匹配版本的无变更操作不追加事件。
191
280
 
192
281
  ## 目标与生命周期权威
193
282
 
194
- `SessionPersistence.inspect()` 提供目标 Session 的观测,且不会发布或恢复 Agent,也不会提交 cold repair。cold 路径先由 `listSnapshots()` 预检明确不存在;已进入目录的 Session 若检查失败,会按基础设施故障原样传播。`put` 只接受具有指定 `MessageId` 的非空、append-origin `assistant/message`;replacement-origin、仅承载 usage 的空记录和非 assistant 记录都不是反馈目标。
283
+ live 持有者的内存日志直接提供目标 Session 的观测;cold 读取使用 `SessionPersistence.open(id, 'read')` 句柄,变更则使用写句柄。两条路径都不构造 Session Agent。先由 `stat(id)` 预检明确不存在;`stat` 已确认存在的 Session 若读取失败,会按基础设施故障原样传播。`put` 只接受具有指定 `MessageId` 的非空、append-origin `assistant/message`;replacement-origin、仅承载 usage 的空记录和非 assistant 记录都不是反馈目标。
195
284
 
196
- 存储的 `{createdAt, cwd}` 身份必须与检查所得 header 匹配。不匹配按不存在处理:`list` 返回空条目,`put` 则可用绑定当前 header 身份的新记录替换陈旧行。fork 使用新的 Session 身份,即使种子包含相同消息,也不获得伴随记录副本。
285
+ fork 种子可以包含父 Session 的反馈事件,但 payload 保留父级 `sessionId`,因此不会成为子 Session 的当前反馈。删除条目会追加删除标记;早先的评分与备注仍保留在日志中。
197
286
 
198
287
  ## 持久化与 Remote 约定
199
288
 
200
- 服务通过 `ctx.storageDomain` 在 `message_feedback` 存储域中保存完整 Session 行。`put` 提交引用目标消息的伴随记录前,身份匹配的 live 目标先经过权威 `ctx.sessions.flush` checkpoint;随后 live 与 cold 路径都会通过 `SessionPersistence.readFrom` 从序列零做物理复读。写入伴随记录前会再次校验所得观测,因此目标日志的持久提交始终先于其伴随记录。`maxNoteBytes` 为必填项,按 UTF-8 字节限制备注文本;Web Host 组合将其设为 `8192`。该包通过 `TypertRemoteService` 与 `@Remote` 发布 Host `messageFeedback.list`、`messageFeedback.put` 和 `messageFeedback.delete` 一元 Remote 约定;下方生成的 Cordis API 是方法级权威。
289
+ 成功的消息反馈变更会等待权威持久化完成:live 操作通过所属 Session 追加,并要求有 `ctx.sessions.flush` 监听器参与;cold 操作通过写句柄追加并 flush。持久化故障会原样传播,不会报告成功。`maxNoteBytes` 为必填项,按 UTF-8 字节限制备注文本;Web Host 组合将其设为 `8192`。该包通过 `TypertRemoteService` 与 `@Remote` 发布 Host `messageFeedback.list`、`messageFeedback.put` 和 `messageFeedback.delete` 一元 Remote 约定;`command-feedback` 以同样方式发布面向 live Session 的 Session 级备注 `sessionFeedback.record`。下方生成的 Cordis API 是方法级权威。
201
290
 
202
- Plugin disposal 会先关闭变更接纳,排空已进入各 Session 队列的工作,然后才关闭 storage domain。
291
+ 插件释放会关闭操作接纳,并排空已进入各 Session 队列的工作。
292
+
293
+ 显式启用后,[`session-log-deepseek`](../../packages/session/session-log-deepseek/README.zh.md) 会在后续符合条件的 DeepSeek 请求中,把反馈作为普通 `dsh_session_log` 后缀的一部分传送。记录反馈不会触发 LLM 请求,也不会单独上传 `dsh_feedback`。对于非 DeepSeek 路由,[OTel 后端](../../packages/session/session-telemetry-otel/README.zh.md)可以将权威日志前缀释放至已记录的反馈。命令确认文本确认记录并标识 Session 与匿名用户,不报告遥测策略或投递结果。
203
294
 
204
295
  ## Web 界面
205
296
 
206
- [`@deepseek-ai/dsh-client-ui-message-feedback`](../../packages/client/ui-message-feedback) 是浏览器侧消费方。`@deepseek-ai/dsh-api-remotes` 挂载生成的 `messageFeedback` 贡献,因此该插件调用 `ctx.remote.messageFeedback`,不接触传输层。
297
+ [`@deepseek-ai/dsh-client-ui-message-feedback`](../../packages/client/ui-message-feedback) 是浏览器侧消费方。`@deepseek-ai/dsh-api-remotes` 挂载生成的 `messageFeedback` 与 `sessionFeedback` 贡献,因此该插件调用 `ctx.remote.messageFeedback` 与 `ctx.remote.sessionFeedback`,不接触传输层。
207
298
 
208
299
  控件是 `conversation.chat.assistant-actions` list slot 的 `feedback` 条目(order 10),该 slot 由 `ui-conversation` 声明,并渲染在已定稿助手消息的 IconActions 行内。`AssistantMessageNode` 携带来自 `assistant/message` 事件的可选 `messageId`。被中断冻结的部分输出没有该字段,渲染点在字段缺失时跳过该 slot。该操作栏每个 Turn 渲染一次,位于收尾的助手消息上:Host 接受每条 append-origin 步骤消息作为目标,但多步骤 Turn 中较早的步骤渲染的是工具行而非可评分正文,因此 UI 暴露的范围比 Host 约定允许的更窄。
209
300
 
210
301
  每个 Session 一个 `MessageFeedbackController`,支撑该 Session 内所有消息的控件:一次 `list` 读取即填充整段对话,且延迟到首次 hover 或 focus 才发起,而非挂载时触发。每次变更把该 controller 最后观察到的版本作为 `ifVersion` 发送;`version-conflict` 响应携带权威条目,controller 据此对账而不重新拉取。变更按 Session 串行,排队操作与已提交版本比较。`connection/reset` 只刷新已读取过的 Session。
211
302
 
303
+ 点赞立即记录不带备注的好评并显示确认 toast。点踩打开该 Session 的反馈弹窗,即 `conversation.input.overlay` 的 `feedback-dialog` 条目:共用的 Modal 卡片,里面是七个分类标签和一个详情框。提交会 put 一条差评,带上所选分类与去除首尾空白的描述,两者也可都不带。不带文本的 `/feedback`(`ui-commands` 以 `action` 路由的一个装饰)为 Session 打开同一个弹窗,随后通过 `sessionFeedback.record` 记录;`/feedback <text>` 仍走宿主命令路径。再次点击已记录的评分会撤回它。
304
+
212
305
  ## 边界与限制
213
306
 
214
- - 变更队列仅在进程内生效。storage-domain 没有跨进程条件写,因此多个 Host 写入同一存储根目录时,不提供 compare-and-swap 或防止丢失更新的保证。
215
- - Session persistence 没有持久删除接口。服务不把 `session/disposed` 或 `api-session/removed` 当作删除,因此不伪造级联;在带外移除日志后,孤儿伴随记录可能继续存在。
307
+ - 操作队列仅在进程内生效;cold 写入排他性依赖所选持久化提供方。
308
+ - 删除只移除当前条目,不会抹除 append-only 日志或已投递后缀中的早先备注。
216
309
  - 请求若恰好落在 live detach 之后、persistence catalog 物化 header 之前的极短窗口,可能收到 `session-not-found`;调用方应在 retirement materialization 后重试。
217
- - 由于 persistence 没有按 id 读取元数据的操作,cold 请求会扫描完整的 Session snapshot 目录。单个 Session 行也没有条目数或聚合字节上限;在具体消费方拥有行策略之前,`maxNoteBytes` 只限制每条备注。
218
- - 只有 `{createdAt, cwd}` 不同时,header 身份才能识别复用的 id;本约定无法区分保留相同 header 身份的克隆日志。
310
+ - cold 请求读取完整日志;服务没有条目数或聚合字节上限。`maxNoteBytes` 只限制每条备注。
219
311
  - Host 约定不记录已认证的 actor 或审计身份,因此假设调用方边界可信。
220
312
  - Web 控件只出现在对话视图。trajectory 与 waterfall 视图不渲染反馈条目,尽管它们的助手节点携带相同的 `messageId`。
221
- - sidecar 不发布实时帧,因此另一个标签页的评分要等到重连或下一次冲突响应才可见,不会立即出现。
222
- - 备注编辑器不预先校验 `maxNoteBytes`;超长备注在保存时以 `note-too-large` 失败,而不是在输入过程中。
313
+ - Web 控制器不消费反馈日志事件,因此另一个标签页的评分要等到重连或下一次冲突响应才可见,不会立即出现。
314
+ - 弹窗不预先校验 `maxNoteBytes`;针对消息的超长描述在提交时以 `note-too-large` 失败,而不是在输入过程中。Session 级备注没有大小上限,`/feedback` 命令从来也没有。
315
+ - `sessionFeedback.record` 只服务 live Session,否则回答 `session-not-found`;弹窗打开期间 Session 退役时,弹窗会报告该失败。
223
316
 
224
317
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
225
318
 
@@ -233,34 +326,75 @@ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnp
233
326
 
234
327
  ### `ctx.messageFeedback` — `MessageFeedbackService`
235
328
 
236
- Storage-domain sidecar service. It inspects persisted Session history and never creates or resumes an Agent or Session.
329
+ Session-log service; cold operations never construct a Session or Agent.
237
330
 
238
331
  ```ts cordis-catalog
239
332
  /**
240
- * Read feedback belonging to the current persisted Session lifecycle.
241
- * A stale row from a reused Session id is invisible.
242
- * @param request - Session identity to inspect and list.
243
- * @returns current immutable items or `session-not-found`.
333
+ * Read current feedback from the canonical log.
334
+ * @param request - Session to inspect.
335
+ * @returns immutable items or a definite persistence miss.
244
336
  */
245
- @Remote('list') async list(request: MessageFeedbackListRequest): Promise<MessageFeedbackListResult>
337
+ @Remote('list') list(request: MessageFeedbackListRequest): Promise<MessageFeedbackListResult>
246
338
 
247
339
  /**
248
- * Create or replace feedback for one derived append-origin assistant
249
- * message. Every request must match the addressed item's current version;
250
- * a matching no-op returns the stored item without changing its revision.
251
- * @param request - target, desired value, and observed item version.
252
- * @returns the committed item or an explicit business failure.
340
+ * Create or replace feedback after checking its current version.
341
+ * Matching no-ops retain the version and append no event.
342
+ * @param request - Target, desired value, and observed item version.
343
+ * @returns the durable item or an explicit business failure.
253
344
  */
254
345
  @Remote('put') put(request: MessageFeedbackPutRequest): Promise<MessageFeedbackPutResult>
255
346
 
256
347
  /**
257
- * Delete one feedback item. Absence is successful regardless of the
258
- * supplied version; an existing item requires an exact version match.
348
+ * Delete one item after checking its version; absence succeeds without an event.
259
349
  * @param request - Session, message, and observed item version.
260
- * @returns the stable absent postcondition, or an explicit failure.
350
+ * @returns the stable absent postcondition or an explicit failure.
261
351
  */
262
352
  @Remote('delete') delete(request: MessageFeedbackDeleteRequest): Promise<MessageFeedbackDeleteResult>
263
353
  ```
264
354
 
355
+ Source: [`packages/feedback/message-feedback/src/index.ts`](../../packages/feedback/message-feedback/src/index.ts)
356
+
357
+ <a id="ctxsessionfeedback--sessionfeedbackservice"></a>
358
+
359
+ ### `ctx.sessionFeedback` — `SessionFeedbackService`
360
+
361
+ Host Remote through which a product surface records a Session-level remark.
362
+
363
+ ```ts cordis-catalog
364
+ /**
365
+ * Record one remark on a live Session.
366
+ * @param request - target Session plus the optional text and category.
367
+ * @returns the recorded postcondition, or `session-not-found` when no live
368
+ * Session carries the id.
369
+ */
370
+ @Remote('record') record(request: SessionFeedbackRecordRequest): Promise<SessionFeedbackRecordResult>
371
+ ```
372
+
373
+ Source: [`packages/feedback/command-feedback/src/index.ts`](../../packages/feedback/command-feedback/src/index.ts)
374
+
375
+ <a id="feedback-events"></a>
376
+
377
+ ### `feedback/*` events
378
+
379
+ <a id="feedbackcommitted--parallel"></a>
380
+
381
+ #### `feedback/committed` — parallel
382
+
383
+ Observe a durable cold feedback mutation without publishing a live Session. Observers run before write ownership is released and must not await another message-feedback operation for this Session. The payload is borrowed read-only; deep-clone it before transferring ownership (for example, to Session.fromRestore).
384
+
385
+ ```ts cordis-catalog
386
+ /**
387
+ * Observe a durable cold feedback mutation without publishing a live Session.
388
+ * Observers run before write ownership is released and must not await
389
+ * another message-feedback operation for this Session. The payload is borrowed
390
+ * read-only; deep-clone it before transferring ownership (for example, to Session.fromRestore).
391
+ * @param inspection - committed canonical prefix, including the feedback as its last event.
392
+ * @mode parallel
393
+ */
394
+ 'feedback/committed'(inspection: SessionInspection): void
395
+ ```
396
+
397
+ Types: [SessionInspection](persistence.zh.md)
398
+
265
399
  Source: [`packages/feedback/message-feedback/src/index.ts`](../../packages/feedback/message-feedback/src/index.ts)
266
400
  <!-- END GENERATED cordis-surface -->