@things-factory/ai-assistant 10.1.27 → 10.1.28

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 (194) hide show
  1. package/client/components/assistant-chat.ts +653 -59
  2. package/client/components/assistant-mode.test.ts +86 -55
  3. package/client/components/assistant-mode.ts +124 -82
  4. package/client/components/chat-echo-dedup.test.ts +23 -0
  5. package/client/components/chat-echo-dedup.ts +29 -3
  6. package/client/components/chat-input-builder.test.ts +20 -20
  7. package/client/components/chat-input-builder.ts +16 -14
  8. package/client/components/chat-proposal-survival.test.ts +73 -0
  9. package/client/components/mention-popup.ts +31 -8
  10. package/client/components/panel-aria.test.ts +34 -0
  11. package/client/components/proposal-outcome-line.ts +33 -0
  12. package/client/utils/assistant-session-controller.test.ts +75 -0
  13. package/client/utils/assistant-session-controller.ts +23 -0
  14. package/client/utils/assistant-session-transport.ts +11 -3
  15. package/dist-client/components/assistant-chat.d.ts +128 -13
  16. package/dist-client/components/assistant-chat.js +613 -67
  17. package/dist-client/components/assistant-chat.js.map +1 -1
  18. package/dist-client/components/assistant-mode.d.ts +80 -68
  19. package/dist-client/components/assistant-mode.js +63 -19
  20. package/dist-client/components/assistant-mode.js.map +1 -1
  21. package/dist-client/components/assistant-mode.test.js +74 -53
  22. package/dist-client/components/assistant-mode.test.js.map +1 -1
  23. package/dist-client/components/chat-echo-dedup.d.ts +2 -0
  24. package/dist-client/components/chat-echo-dedup.js +27 -4
  25. package/dist-client/components/chat-echo-dedup.js.map +1 -1
  26. package/dist-client/components/chat-echo-dedup.test.js +20 -0
  27. package/dist-client/components/chat-echo-dedup.test.js.map +1 -1
  28. package/dist-client/components/chat-input-builder.d.ts +12 -7
  29. package/dist-client/components/chat-input-builder.js +8 -10
  30. package/dist-client/components/chat-input-builder.js.map +1 -1
  31. package/dist-client/components/chat-input-builder.test.js +17 -18
  32. package/dist-client/components/chat-input-builder.test.js.map +1 -1
  33. package/dist-client/components/chat-proposal-survival.test.d.ts +1 -0
  34. package/dist-client/components/chat-proposal-survival.test.js +61 -0
  35. package/dist-client/components/chat-proposal-survival.test.js.map +1 -0
  36. package/dist-client/components/mention-popup.js +28 -8
  37. package/dist-client/components/mention-popup.js.map +1 -1
  38. package/dist-client/components/panel-aria.test.d.ts +1 -0
  39. package/dist-client/components/panel-aria.test.js +31 -0
  40. package/dist-client/components/panel-aria.test.js.map +1 -0
  41. package/dist-client/components/proposal-outcome-line.d.ts +9 -0
  42. package/dist-client/components/proposal-outcome-line.js +15 -0
  43. package/dist-client/components/proposal-outcome-line.js.map +1 -0
  44. package/dist-client/tsconfig.tsbuildinfo +1 -1
  45. package/dist-client/utils/assistant-session-controller.d.ts +10 -0
  46. package/dist-client/utils/assistant-session-controller.js +16 -0
  47. package/dist-client/utils/assistant-session-controller.js.map +1 -1
  48. package/dist-client/utils/assistant-session-controller.test.d.ts +1 -0
  49. package/dist-client/utils/assistant-session-controller.test.js +56 -0
  50. package/dist-client/utils/assistant-session-controller.test.js.map +1 -0
  51. package/dist-client/utils/assistant-session-transport.js +11 -3
  52. package/dist-client/utils/assistant-session-transport.js.map +1 -1
  53. package/dist-server/service/assistant-capability-resolver.d.ts +17 -0
  54. package/dist-server/service/assistant-capability-resolver.js +88 -0
  55. package/dist-server/service/assistant-capability-resolver.js.map +1 -0
  56. package/dist-server/service/assistant-chat-resolver.d.ts +6 -6
  57. package/dist-server/service/assistant-chat-resolver.js +166 -44
  58. package/dist-server/service/assistant-chat-resolver.js.map +1 -1
  59. package/dist-server/service/assistant-mode/assistant-mode-resolver.d.ts +25 -0
  60. package/dist-server/service/assistant-mode/assistant-mode-resolver.js +140 -0
  61. package/dist-server/service/assistant-mode/assistant-mode-resolver.js.map +1 -0
  62. package/dist-server/service/assistant-mode/index.d.ts +9 -0
  63. package/dist-server/service/assistant-mode/index.js +19 -0
  64. package/dist-server/service/assistant-mode/index.js.map +1 -0
  65. package/dist-server/service/assistant-mode/registry.d.ts +18 -0
  66. package/dist-server/service/assistant-mode/registry.js +136 -0
  67. package/dist-server/service/assistant-mode/registry.js.map +1 -0
  68. package/dist-server/service/assistant-mode/resolve.d.ts +33 -0
  69. package/dist-server/service/assistant-mode/resolve.js +60 -0
  70. package/dist-server/service/assistant-mode/resolve.js.map +1 -0
  71. package/dist-server/service/assistant-mode/types.d.ts +99 -0
  72. package/dist-server/service/assistant-mode/types.js +12 -0
  73. package/dist-server/service/assistant-mode/types.js.map +1 -0
  74. package/dist-server/service/chat-message/carried-turns.d.ts +48 -0
  75. package/dist-server/service/chat-message/carried-turns.js +80 -0
  76. package/dist-server/service/chat-message/carried-turns.js.map +1 -0
  77. package/dist-server/service/chat-message/chat-message-subscription.d.ts +1 -1
  78. package/dist-server/service/chat-message/chat-message-subscription.js +24 -6
  79. package/dist-server/service/chat-message/chat-message-subscription.js.map +1 -1
  80. package/dist-server/service/chat-message/chat-message.d.ts +32 -0
  81. package/dist-server/service/chat-message/chat-message.js +17 -0
  82. package/dist-server/service/chat-message/chat-message.js.map +1 -1
  83. package/dist-server/service/chat-message/door-access.d.ts +15 -0
  84. package/dist-server/service/chat-message/door-access.js +26 -0
  85. package/dist-server/service/chat-message/door-access.js.map +1 -0
  86. package/dist-server/service/chat-message/fold-session-history.d.ts +30 -0
  87. package/dist-server/service/chat-message/fold-session-history.js +133 -0
  88. package/dist-server/service/chat-message/fold-session-history.js.map +1 -0
  89. package/dist-server/service/chat-message/llm-history.d.ts +7 -0
  90. package/dist-server/service/chat-message/llm-history.js +23 -11
  91. package/dist-server/service/chat-message/llm-history.js.map +1 -1
  92. package/dist-server/service/chat-message/message-doors.d.ts +29 -0
  93. package/dist-server/service/chat-message/message-doors.js +107 -0
  94. package/dist-server/service/chat-message/message-doors.js.map +1 -0
  95. package/dist-server/service/chat-message/proposal-outcome.d.ts +18 -0
  96. package/dist-server/service/chat-message/proposal-outcome.js +31 -0
  97. package/dist-server/service/chat-message/proposal-outcome.js.map +1 -0
  98. package/dist-server/service/chat-message/reader-gate.d.ts +3 -0
  99. package/dist-server/service/chat-message/reader-gate.js +37 -0
  100. package/dist-server/service/chat-message/reader-gate.js.map +1 -0
  101. package/dist-server/service/chat-message/room-message.d.ts +4 -0
  102. package/dist-server/service/chat-message/room-message.js +25 -0
  103. package/dist-server/service/chat-message/room-message.js.map +1 -0
  104. package/dist-server/service/chat-session/chat-session.d.ts +24 -0
  105. package/dist-server/service/chat-session/chat-session.js +26 -2
  106. package/dist-server/service/chat-session/chat-session.js.map +1 -1
  107. package/dist-server/service/chat-session/session-inbox.d.ts +4 -1
  108. package/dist-server/service/chat-session/session-inbox.js +3 -2
  109. package/dist-server/service/chat-session/session-inbox.js.map +1 -1
  110. package/dist-server/service/chat-session/session-visibility.d.ts +15 -0
  111. package/dist-server/service/chat-session/session-visibility.js +28 -0
  112. package/dist-server/service/chat-session/session-visibility.js.map +1 -0
  113. package/dist-server/service/chat-session/station-session-guard.d.ts +1 -5
  114. package/dist-server/service/chat-session/station-session-guard.js +7 -2
  115. package/dist-server/service/chat-session/station-session-guard.js.map +1 -1
  116. package/dist-server/service/chat-session-participant/mention-invite.d.ts +29 -0
  117. package/dist-server/service/chat-session-participant/mention-invite.js +103 -0
  118. package/dist-server/service/chat-session-participant/mention-invite.js.map +1 -0
  119. package/dist-server/service/chat-session-resolver.d.ts +15 -0
  120. package/dist-server/service/chat-session-resolver.js +267 -15
  121. package/dist-server/service/chat-session-resolver.js.map +1 -1
  122. package/dist-server/service/grounding-sources.d.ts +14 -0
  123. package/dist-server/service/grounding-sources.js +26 -0
  124. package/dist-server/service/grounding-sources.js.map +1 -0
  125. package/dist-server/service/index.d.ts +8 -1
  126. package/dist-server/service/index.js +19 -0
  127. package/dist-server/service/index.js.map +1 -1
  128. package/dist-server/service/request-translator.d.ts +2 -0
  129. package/dist-server/service/request-translator.js +20 -0
  130. package/dist-server/service/request-translator.js.map +1 -0
  131. package/dist-server/service/testing/conversation-script.d.ts +123 -0
  132. package/dist-server/service/testing/conversation-script.js +202 -0
  133. package/dist-server/service/testing/conversation-script.js.map +1 -0
  134. package/dist-server/service/testing/mode-conformance.d.ts +40 -0
  135. package/dist-server/service/testing/mode-conformance.js +90 -0
  136. package/dist-server/service/testing/mode-conformance.js.map +1 -0
  137. package/dist-server/tool-registry-boot-report.d.ts +3 -0
  138. package/dist-server/tool-registry-boot-report.js +25 -2
  139. package/dist-server/tool-registry-boot-report.js.map +1 -1
  140. package/dist-server/tsconfig.tsbuildinfo +1 -1
  141. package/package.json +5 -5
  142. package/server/explicit-graphql-types.test.ts +56 -0
  143. package/server/service/assistant-capability-resolver.ts +66 -0
  144. package/server/service/assistant-chat-resolver.ts +184 -42
  145. package/server/service/assistant-mode/assistant-mode-resolver.ts +102 -0
  146. package/server/service/assistant-mode/index.ts +16 -0
  147. package/server/service/assistant-mode/registry.test.ts +105 -0
  148. package/server/service/assistant-mode/registry.ts +147 -0
  149. package/server/service/assistant-mode/resolve.test.ts +78 -0
  150. package/server/service/assistant-mode/resolve.ts +96 -0
  151. package/server/service/assistant-mode/subject-defaults.test.ts +86 -0
  152. package/server/service/assistant-mode/types.ts +103 -0
  153. package/server/service/chat-message/carried-turns.test.ts +69 -0
  154. package/server/service/chat-message/carried-turns.ts +99 -0
  155. package/server/service/chat-message/chat-message-subscription.ts +20 -4
  156. package/server/service/chat-message/chat-message.ts +44 -0
  157. package/server/service/chat-message/door-access.ts +45 -0
  158. package/server/service/chat-message/fold-session-history.test.ts +98 -0
  159. package/server/service/chat-message/fold-session-history.ts +115 -0
  160. package/server/service/chat-message/llm-history.test.ts +58 -7
  161. package/server/service/chat-message/llm-history.ts +30 -11
  162. package/server/service/chat-message/message-doors.test.ts +87 -0
  163. package/server/service/chat-message/message-doors.ts +117 -0
  164. package/server/service/chat-message/proposal-outcome.test.ts +48 -0
  165. package/server/service/chat-message/proposal-outcome.ts +42 -0
  166. package/server/service/chat-message/reader-gate.ts +42 -0
  167. package/server/service/chat-message/room-message.test.ts +21 -0
  168. package/server/service/chat-message/room-message.ts +22 -0
  169. package/server/service/chat-session/chat-session.ts +31 -1
  170. package/server/service/chat-session/session-inbox.test.ts +18 -0
  171. package/server/service/chat-session/session-inbox.ts +9 -2
  172. package/server/service/chat-session/session-visibility.test.ts +36 -0
  173. package/server/service/chat-session/session-visibility.ts +26 -0
  174. package/server/service/chat-session/station-session-guard.ts +10 -2
  175. package/server/service/chat-session-participant/mention-invite.test.ts +125 -0
  176. package/server/service/chat-session-participant/mention-invite.ts +121 -0
  177. package/server/service/chat-session-resolver.ts +272 -15
  178. package/server/service/grounding-sources.test.ts +55 -0
  179. package/server/service/grounding-sources.ts +46 -0
  180. package/server/service/index.ts +19 -0
  181. package/server/service/request-translator.test.ts +45 -0
  182. package/server/service/request-translator.ts +33 -0
  183. package/server/service/station-session-guard.test.ts +12 -5
  184. package/server/service/testing/conversation-scenario.test.ts +163 -0
  185. package/server/service/testing/conversation-script.test.ts +131 -0
  186. package/server/service/testing/conversation-script.ts +288 -0
  187. package/server/service/testing/mode-conformance.ts +107 -0
  188. package/server/tool-registry-boot-report.ts +25 -2
  189. package/test/assistant-chat-call-sites.test.ts +82 -0
  190. package/translations/en.json +44 -2
  191. package/translations/ja.json +44 -2
  192. package/translations/ko.json +44 -2
  193. package/translations/ms.json +44 -2
  194. package/translations/zh.json +44 -2
@@ -81,8 +81,10 @@ export declare class OxAssistantChat extends LitElement {
81
81
  * `@` mention 도메인 사용자 공급자 (선택). 호스트가 `domainUsersForMention` query 로 wrap.
82
82
  *
83
83
  * 호스트는 query 문자열을 받아 도메인 사용자 후보 (id/name/email) 배열을 돌려준다.
84
- * 미설정 시 `@` popup 은 빈 결과 (사용자가 멘션 못 함). 멀티유저 환경 활성화 정책에 따라
85
- * 호스트가 set 해야 활성화. async 자연스러우므로 Promise 반환 가능.
84
+ *
85
+ * **미설정이면 대화창이 패키지의 문(`domainUsersForMention`)에 직접 묻는다.** 예전에는
86
+ * 결과였고, 그래서 앱 셋에서는 `@이름` 을 고를 수 없었다 — 멘션이 사람을 불러들이는 길을 세워도
87
+ * 부르는 자리가 없었다. 자기 목록을 따로 쓰는 호스트만 이것을 준다.
86
88
  */
87
89
  userProvider?: (query: string) => Promise<Array<{
88
90
  id: string;
@@ -114,22 +116,28 @@ export declare class OxAssistantChat extends LitElement {
114
116
  hostContext?: any;
115
117
  /** 코어 보드 편집 도구 사용 여부. 기본 true. 보드를 고칠 이유가 없는 면에서 false. */
116
118
  boardTools: boolean;
117
- chatEndpoint: 'boardAIChat' | 'assistantChat';
118
- /**
119
- * Who the assistant is on this surface, in the host's words. Required by `assistantChat`; the
120
- * board conversation carries its own persona on the server and ignores this.
121
- */
119
+ chatEndpoint?: 'boardAIChat' | 'assistantChat';
122
120
  /**
123
121
  * What this conversation is — see `AssistantMode`.
124
122
  *
125
- * A host that sets this does not set `systemPrompt`, `toolCategories`, `hostContext` or
126
- * `chatEndpoint` separately, and does not rely on `registerChatDefaults` for its `@` and `/`
127
- * lists: the mode carries all of them together, so they cannot disagree with each other.
123
+ * A host that sets this sets nothing else about the conversation: the persona, the tool
124
+ * categories, the model and the limits belong to the mode its app server registered, and what
125
+ * `@` and `/` offer comes from that same declaration, translated. They cannot disagree because
126
+ * there is one of them.
128
127
  *
129
- * When `mode.id` changes the conversation on screen is closed and a new one begins.
128
+ * When `kind` or `target` changes the conversation on screen is closed and a new one begins.
130
129
  */
131
130
  mode?: AssistantMode;
132
- systemPrompt?: string;
131
+ /**
132
+ * 이 화면이 보여 주는 것의 **종류** — `'board'`, `'space'`, `'station'`, `'figure'` (ADR-0072 A17 ①).
133
+ *
134
+ * `mode` 가 「지금 어느 대화인가」라면 이것은 「그 자리에 어떤 대화들이 설 수 있나」이다. 서버가
135
+ * `assistantModes(subject)` 로 답하고, 둘 이상이면 고르개가 뜬다. 하나면 고르개를 내지 않는다 —
136
+ * 고를 것이 없는 고르개는 자리만 차지한다.
137
+ *
138
+ * 화면이 이것을 안 주면 고르개는 없고 host 가 정한 대화 하나만 산다. 그것이 오늘까지의 모양이다.
139
+ */
140
+ subject?: string;
133
141
  /**
134
142
  * 라이브 상태를 다루는 대화면인가 — true 면 **첫 턴에 도구 호출을 강제**한다.
135
143
  *
@@ -152,7 +160,7 @@ export declare class OxAssistantChat extends LitElement {
152
160
  group?: string;
153
161
  properties?: Record<string, any>;
154
162
  }>;
155
- placeholder: string;
163
+ placeholder?: string;
156
164
  private lines;
157
165
  private input;
158
166
  /**
@@ -263,6 +271,7 @@ export declare class OxAssistantChat extends LitElement {
263
271
  * email 을 쓰는 이유: /auth/profile 이 항상 내려주는 로그인 식별자이고(비어 있지 않다),
264
272
  * 내부 관리키(User.id)를 클라이언트 판정에 의존하지 않기 위함. */
265
273
  private get _myEmail();
274
+ private get _myUserId();
266
275
  /** Mention popup — `#` (컴포넌트) / `@` (카탈로그) / `/` (slash) 트리거 시 활성.
267
276
  * 단일 popup 재사용 — mentionTrigger 로 활성 trigger 추적. */
268
277
  private mentionOpen;
@@ -291,6 +300,35 @@ export declare class OxAssistantChat extends LitElement {
291
300
  /** centerTo 디바운스 timer — arrow nav / hover 빠를 때 카메라 애니메이션 race 방지 */
292
301
  private centerDebounceTimer?;
293
302
  private get conversation();
303
+ /**
304
+ * What the server said this mode offers, in this person's language.
305
+ *
306
+ * Fetched when the mode changes and kept until the next one answers. Until it arrives the panel
307
+ * offers nothing rather than the list some other package registered globally.
308
+ */
309
+ private modeView?;
310
+ private modeViewToken;
311
+ /** 이 subject 에 설 수 있는 대화들 — 기본이 먼저. 하나뿐이면 고르개를 그리지 않는다. */
312
+ private modeChoices;
313
+ private modeChoicesToken;
314
+ /**
315
+ * 이 화면에 설 수 있는 대화를 서버에 묻는다.
316
+ *
317
+ * 화면이 종류 목록을 손에 들고 있으면, 대화를 하나 더 세운 날 그 화면만 모른 채로 남는다. 목록은
318
+ * 앱 서버의 선언에서 나온다(ADR-0072 A17 ①).
319
+ */
320
+ private loadModeChoices;
321
+ /**
322
+ * 사람이 다른 대화를 골랐다.
323
+ *
324
+ * 고른 것은 **이 subject 종류에 대해** 기억한다 — 보드를 열 때마다 저작 대화로 돌아가면, 현장을
325
+ * 물으려던 사람은 화면을 열 때마다 같은 손질을 다시 해야 한다. 기억은 이 브라우저에만 남는다
326
+ * (서버에 칸을 만들지 않는다 — A17 ①). 세션 자체는 자기가 어느 대화였는지 이미 안다.
327
+ */
328
+ private onModePick;
329
+ /** 이 subject 에서 지난번에 고른 대화 — 없으면 undefined. */
330
+ private rememberedMode;
331
+ private loadModeView;
294
332
  private cachedCatalogCandidates;
295
333
  private cachedSlashCandidates;
296
334
  private rebuildMentionCaches;
@@ -301,6 +339,13 @@ export declare class OxAssistantChat extends LitElement {
301
339
  private userFetchToken;
302
340
  static styles: import("lit").CSSResult[];
303
341
  connectedCallback(): void;
342
+ /**
343
+ * 화면이 보여 주는 것의 종류가 바뀌었다 — 설 수 있는 대화를 다시 묻고, 지난번 고른 것을 되살린다.
344
+ *
345
+ * 되살리는 것은 **고른 대화**이지 세션이 아니다. 세션은 자기가 어느 대화였는지 이미 알고, 다른
346
+ * 대화로 가면 그때 새로 난다(ADR-0072 A17 ①).
347
+ */
348
+ private onSubjectChanged;
304
349
  updated(changed: Map<string, any>): void;
305
350
  disconnectedCallback(): void;
306
351
  private _startPresence;
@@ -325,6 +370,23 @@ export declare class OxAssistantChat extends LitElement {
325
370
  private _isOnline;
326
371
  private loadHistory;
327
372
  render(): import("lit-html").TemplateResult<1>;
373
+ /**
374
+ * 방에 말한다 — 어시스턴트는 답하지 않는다.
375
+ *
376
+ * 저장되는 대화가 있을 때만 할 수 있다. 세션이 없는 즉석 질문에는 「방」이 없다 — 그 자리에서
377
+ * 한 말은 누구에게도 남지 않는다.
378
+ */
379
+ private sayToRoom;
380
+ /**
381
+ * 보내기 전에 말한다 — 「이 사람은 이 대화에 들어옵니다」(ADR-0071 결정 1 ④).
382
+ *
383
+ * 멘션은 사람을 불러들인다. 누른 뒤에 알면 이미 들어와 있고, 협의의 공개 범위는 되돌리기 어려운
384
+ * 종류의 일이다. 그래서 **아직 보내지 않은 상태에서** 누가 들어오게 되는지 보인다.
385
+ *
386
+ * 초대할 수 없는 자리(보기 권한 · 아직 참여자가 아님)라면 그 사실을 말한다 — 눌렀는데 아무 일도
387
+ * 일어나지 않는 것이 가장 나쁘다.
388
+ */
389
+ private renderInviteNotice;
328
390
  private onKeyDown;
329
391
  /** input 이벤트 — value 즉시 반영 + popup 갱신은 150ms 디바운스 (F-Finder 와 동일).
330
392
  * big board 에서 매 keystroke filter 비용 절감 + 한국어 IME 조합 중 깜빡임 완화. */
@@ -332,6 +394,12 @@ export declare class OxAssistantChat extends LitElement {
332
394
  /** 현재 cursor 위치를 보고 mention popup 활성/비활성 + 후보 갱신.
333
395
  * `#` (컴포넌트) / `@` (카탈로그) / `/` (slash 템플릿) 한 번에 하나만 활성. */
334
396
  private refreshMentionPopup;
397
+ /**
398
+ * 호스트가 목록을 주지 않을 때 이 도메인의 사용자를 직접 묻는다.
399
+ *
400
+ * 실패는 빈 목록이다 — 멘션을 못 고르는 것이지 대화가 막힐 일은 아니다.
401
+ */
402
+ private fetchDomainUsers;
335
403
  /** `@` query 에 대한 userProvider 비동기 호출 — 응답 도착 시 popup 결과 갱신.
336
404
  * race 방지: token 으로 최신 호출 식별 (늦게 도착한 응답 무시). */
337
405
  private refreshUserCandidatesAsync;
@@ -369,6 +437,29 @@ export declare class OxAssistantChat extends LitElement {
369
437
  private static readonly EXAMPLE_GROUPS;
370
438
  /** 보드의 세션 탭 — 다중 세션 활성화 시 패널 상단. host 가 sessions 비워두면 표시 X.
371
439
  * 레이블은 session.name 우선, 없으면 fallback "세션 N". */
440
+ /**
441
+ * 이 대화의 **주어** — 같은 화면 위에 두 대화가 설 때만 나온다(ADR-0072 A17 ①).
442
+ *
443
+ * 하나뿐이면 아무것도 그리지 않는다. 고를 것이 없는 고르개는 자리만 차지하고, 사람에게 「무언가
444
+ * 고를 것이 있다」는 잘못된 신호를 준다.
445
+ *
446
+ * ── 왜 탭 줄이 아닌가 (UX 레인, 2026-09-18) ───────────────────────────────
447
+ * 처음에는 칩 줄에 `role="tablist"` 를 달았다. 바로 아래가 세션 탭이고 그쪽도 tablist 라서, 화면
448
+ * 낭독기로 들으면 「탭 목록, 대화」 다음에 「탭 목록, Conversation history」 가 이어졌다 — 고르는
449
+ * 축이 둘인데 둘 다 「탭」이라고 말한다. 게다가 ARIA 탭은 좌우 화살표 이동과 `tabpanel` 이 함께
450
+ * 있어야 성립하고, 둘 다 없으면 낭독기는 「2 중 1번째 탭」이라 말하고 화살표는 아무 일도 안 한다.
451
+ *
452
+ * 무게도 다르다. 세션은 「어느 지난 대화냐」이고 모드는 「이 대화가 무엇에 대한 것이냐」이다. 같은
453
+ * 무게로 그리면 어느 쪽이 화제를 바꾸고 어느 쪽이 실타래를 바꾸는지 구별되지 않는다. 그래서 지금
454
+ * 대화가 제목 굵기로 서고, 바꿀 자리는 그 옆에 붙는다.
455
+ *
456
+ * ── 왜 도크 제목 줄로 안 올리나 (UX 레인 판정, 2026-09-18) ────────────────
457
+ * 도크 제목은 「지금 어디에 있나」(이 도형 · 이 현장 · 이 스테이션 화면)이고 이 줄은 「이 대화가
458
+ * 무엇에 대한 것이냐」이다. 대화의 주어는 대화 안에 있다. 그리고 세 도크가 각자 그리면 세 벌이 되고
459
+ * 그 세 벌은 갈린다 — `modeChoices` 를 아는 것도 여기다. 올리면 목록과 고른 것이 세 자리로 나갔다
460
+ * 돌아온다.
461
+ */
462
+ private renderModeSubject;
372
463
  private renderSessionTabs;
373
464
  /** C4 roster — 세션 참여자 + online 표시. 참여자 2명 미만이면 숨김(혼자면 의미 없음). */
374
465
  private renderRoster;
@@ -411,6 +502,13 @@ export declare class OxAssistantChat extends LitElement {
411
502
  * 실행 결과는 호스트가 **대화에 기록**한다 — 누가 무엇을 실행했는지가 협의 이력에 남아야 한다.
412
503
  */
413
504
  private renderProposals;
505
+ /**
506
+ * 눌린 카드가 말하는 것 — **호스트가 한 일**이고, 아직 모르면 모른다고 말한다.
507
+ *
508
+ * 예전에는 누른 순간 「실행됨」이었다. 09-18 트윈에서 아무 일도 일어나지 않은 채 「✓ 반영했습니다」가
509
+ * 떴다(ADR-0070 A12-a).
510
+ */
511
+ private proposalStateText;
414
512
  private onChoiceClick;
415
513
  /**
416
514
  * 제안 식별 키 — 같은 조치를 두 번 실행하지 않도록 **효과**(명령·대상·인자)로만 만든다.
@@ -424,7 +522,24 @@ export declare class OxAssistantChat extends LitElement {
424
522
  * 실행은 호스트가 한다 — 이 컴포넌트는 도메인(트윈 명령 채널)을 모른다.
425
523
  * 확인 대화·명령 전송·결과 기록은 호스트의 몫이고, 여기서는 중복 클릭만 막는다.
426
524
  */
525
+ /**
526
+ * 누른 시각 — 「보내는 중」 옆의 경과 시간용.
527
+ *
528
+ * 시간으로 실패를 판정하지 않는다(ADR-0070 A12-a 결정 ②). 아는 사실은 「아직 답을 받지 못했다」
529
+ * 하나이고, 시간이 지났다고 실패로 바꾸면 그것이 지어낸 원인이다.
530
+ */
531
+ private proposalSentAt;
532
+ private elapsedTimer?;
427
533
  private executeProposal;
534
+ /**
535
+ * 호스트가 무엇을 했는지 — 대화에 남은 `system` 행에서 읽는다(ADR-0070 A12-a 결정 ①).
536
+ *
537
+ * 카드가 자기 기억으로 상태를 들고 있으면 새로 고치는 순간 사라지고, 다른 창에서 실행한 것은
538
+ * 애초에 보이지 않는다. 그래서 상태의 자리는 이력이다.
539
+ */
540
+ private get proposalOutcomes();
541
+ /** 경과 시간을 보이는 동안에만 돈다 — 답이 오면 멈춘다. */
542
+ private _startElapsedTicker;
428
543
  /**
429
544
  * 접지 경고 — 답이 언급했지만 **근거에 없던** 대상을 알린다.
430
545
  *