@yadsh/dsh-qa-surface 0.6.1 → 0.7.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 (281) hide show
  1. package/README.md +136 -7
  2. package/capability-policy.json +1 -1
  3. package/lib/access/capability-catalog.js +144 -0
  4. package/lib/access/capability-catalog.js.map +1 -0
  5. package/lib/access/model.js +379 -0
  6. package/lib/access/model.js.map +1 -0
  7. package/lib/access/role-repository.js +195 -0
  8. package/lib/access/role-repository.js.map +1 -0
  9. package/lib/access/service.js +380 -0
  10. package/lib/access/service.js.map +1 -0
  11. package/lib/access/skill-metadata.js +234 -0
  12. package/lib/access/skill-metadata.js.map +1 -0
  13. package/lib/account-remotes.js +20 -10
  14. package/lib/account-remotes.js.map +1 -1
  15. package/lib/accounts/errors.js.map +1 -1
  16. package/lib/accounts/file.js.map +1 -1
  17. package/lib/accounts/store.js +202 -3
  18. package/lib/accounts/store.js.map +1 -1
  19. package/lib/admin/conversation-log.js +256 -0
  20. package/lib/admin/conversation-log.js.map +1 -0
  21. package/lib/admin/index.js +17 -0
  22. package/lib/admin/index.js.map +1 -0
  23. package/lib/admin/metrics.js +103 -0
  24. package/lib/admin/metrics.js.map +1 -0
  25. package/lib/admin/paging.js +23 -0
  26. package/lib/admin/paging.js.map +1 -0
  27. package/lib/admin/permissions.js +50 -0
  28. package/lib/admin/permissions.js.map +1 -0
  29. package/lib/admin/quality-store.js +485 -0
  30. package/lib/admin/quality-store.js.map +1 -0
  31. package/lib/admin/queue.js +107 -0
  32. package/lib/admin/queue.js.map +1 -0
  33. package/lib/admin/redaction.js +45 -0
  34. package/lib/admin/redaction.js.map +1 -0
  35. package/lib/admin/service.js +897 -0
  36. package/lib/admin/service.js.map +1 -0
  37. package/lib/admin/session-log.js +142 -0
  38. package/lib/admin/session-log.js.map +1 -0
  39. package/lib/cli.js +9 -6
  40. package/lib/cli.js.map +1 -1
  41. package/lib/client/QaSessionController.js +28 -2
  42. package/lib/client/QaSessionController.js.map +1 -1
  43. package/lib/client/QaSurface.js +143 -5
  44. package/lib/client/QaSurface.js.map +1 -1
  45. package/lib/client/QaTranscriptAdapter.js +1 -0
  46. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  47. package/lib/client/admin/QaAdmin.js +458 -0
  48. package/lib/client/admin/QaAdmin.js.map +1 -0
  49. package/lib/client/admin/format.js +177 -0
  50. package/lib/client/admin/format.js.map +1 -0
  51. package/lib/client/admin/pages/Conversations.js +114 -0
  52. package/lib/client/admin/pages/Conversations.js.map +1 -0
  53. package/lib/client/admin/pages/Overview.js +24 -0
  54. package/lib/client/admin/pages/Overview.js.map +1 -0
  55. package/lib/client/admin/pages/Quality.js +71 -0
  56. package/lib/client/admin/pages/Quality.js.map +1 -0
  57. package/lib/client/admin/pages/Review.js +93 -0
  58. package/lib/client/admin/pages/Review.js.map +1 -0
  59. package/lib/client/admin/pages/Users.js +95 -0
  60. package/lib/client/admin/pages/Users.js.map +1 -0
  61. package/lib/client/admin/routes.js +127 -0
  62. package/lib/client/admin/routes.js.map +1 -0
  63. package/lib/client/admin/shared.js +91 -0
  64. package/lib/client/admin/shared.js.map +1 -0
  65. package/lib/client/admin/styles.js +111 -0
  66. package/lib/client/admin/styles.js.map +1 -0
  67. package/lib/client/components/QaChangelog.js +35 -0
  68. package/lib/client/components/QaChangelog.js.map +1 -1
  69. package/lib/client/components/QaHeader.js +3 -3
  70. package/lib/client/components/QaHeader.js.map +1 -1
  71. package/lib/client/components/QaMessage.js +61 -2
  72. package/lib/client/components/QaMessage.js.map +1 -1
  73. package/lib/client/create-session.js +1 -1
  74. package/lib/client/create-session.js.map +1 -1
  75. package/lib/client/index.js +33 -1
  76. package/lib/client/index.js.map +1 -1
  77. package/lib/client/role/RoleSelector.js +31 -0
  78. package/lib/client/role/RoleSelector.js.map +1 -0
  79. package/lib/client/session-sources.js +37 -1
  80. package/lib/client/session-sources.js.map +1 -1
  81. package/lib/client/settings/card.js +2 -2
  82. package/lib/client/settings/card.js.map +1 -1
  83. package/lib/client/settings/sections.js +0 -1
  84. package/lib/client/settings/sections.js.map +1 -1
  85. package/lib/client/styles.js +31 -0
  86. package/lib/client/styles.js.map +1 -1
  87. package/lib/client/types.js.map +1 -1
  88. package/lib/client.js +9908 -4857
  89. package/lib/client.js.map +1 -1
  90. package/lib/config-resolvers/defaults.js +0 -2
  91. package/lib/config-resolvers/defaults.js.map +1 -1
  92. package/lib/config.js +0 -249
  93. package/lib/config.js.map +1 -1
  94. package/lib/enforcement/skill-policy.js +172 -0
  95. package/lib/enforcement/skill-policy.js.map +1 -0
  96. package/lib/enforcement/tool-grants.js +151 -0
  97. package/lib/enforcement/tool-grants.js.map +1 -0
  98. package/lib/index.js +224 -42
  99. package/lib/index.js.map +1 -1
  100. package/lib/personal-skills/service.js +10 -3
  101. package/lib/personal-skills/service.js.map +1 -1
  102. package/lib/qa-tools/index.js +4 -0
  103. package/lib/qa-tools/index.js.map +1 -1
  104. package/lib/resolve-config.js +0 -2
  105. package/lib/resolve-config.js.map +1 -1
  106. package/lib/secure-session.js +71 -17
  107. package/lib/secure-session.js.map +1 -1
  108. package/lib/typert.host.js +2237 -202
  109. package/lib/typert.remote-client.d.ts +49 -3
  110. package/lib/typert.remote-client.js +1863 -183
  111. package/lib/types/access/capability-catalog.d.ts +37 -0
  112. package/lib/types/access/model.d.ts +60 -0
  113. package/lib/types/access/role-repository.d.ts +32 -0
  114. package/lib/types/access/service.d.ts +57 -0
  115. package/lib/types/access/skill-metadata.d.ts +53 -0
  116. package/lib/types/account-remotes.d.ts +6 -0
  117. package/lib/types/accounts/errors.d.ts +1 -1
  118. package/lib/types/accounts/file.d.ts +16 -5
  119. package/lib/types/accounts/store.d.ts +83 -3
  120. package/lib/types/admin/conversation-log.d.ts +39 -0
  121. package/lib/types/admin/index.d.ts +24 -0
  122. package/lib/types/admin/metrics.d.ts +29 -0
  123. package/lib/types/admin/paging.d.ts +33 -0
  124. package/lib/types/admin/permissions.d.ts +10 -0
  125. package/lib/types/admin/quality-store.d.ts +82 -0
  126. package/lib/types/admin/queue.d.ts +21 -0
  127. package/lib/types/admin/redaction.d.ts +29 -0
  128. package/lib/types/admin/service.d.ts +105 -0
  129. package/lib/types/admin/session-log.d.ts +53 -0
  130. package/lib/types/client/QaSessionController.d.ts +12 -1
  131. package/lib/types/client/QaSurface.d.ts +7 -1
  132. package/lib/types/client/admin/QaAdmin.d.ts +17 -0
  133. package/lib/types/client/admin/format.d.ts +43 -0
  134. package/lib/types/client/admin/pages/Conversations.d.ts +21 -0
  135. package/lib/types/client/admin/pages/Overview.d.ts +13 -0
  136. package/lib/types/client/admin/pages/Quality.d.ts +18 -0
  137. package/lib/types/client/admin/pages/Review.d.ts +15 -0
  138. package/lib/types/client/admin/pages/Users.d.ts +22 -0
  139. package/lib/types/client/admin/routes.d.ts +50 -0
  140. package/lib/types/client/admin/shared.d.ts +53 -0
  141. package/lib/types/client/admin/styles.d.ts +11 -0
  142. package/lib/types/client/components/QaHeader.d.ts +5 -1
  143. package/lib/types/client/components/QaMessage.d.ts +14 -1
  144. package/lib/types/client/create-session.d.ts +2 -0
  145. package/lib/types/client/role/RoleSelector.d.ts +14 -0
  146. package/lib/types/client/session-sources.d.ts +9 -0
  147. package/lib/types/client/settings/sections.d.ts +0 -1
  148. package/lib/types/client/types.d.ts +39 -2
  149. package/lib/types/enforcement/skill-policy.d.ts +29 -0
  150. package/lib/types/enforcement/tool-grants.d.ts +84 -0
  151. package/lib/types/index.d.ts +62 -14
  152. package/lib/types/qa-tools/index.d.ts +2 -0
  153. package/lib/types/secure-session.d.ts +10 -1
  154. package/lib/types/types.d.ts +568 -5
  155. package/package.json +1 -1
  156. package/lib/client/settings/sections/documents.js +0 -88
  157. package/lib/client/settings/sections/documents.js.map +0 -1
  158. package/lib/documents/artifacts/ids.js +0 -43
  159. package/lib/documents/artifacts/ids.js.map +0 -1
  160. package/lib/documents/artifacts/manifest.js +0 -66
  161. package/lib/documents/artifacts/manifest.js.map +0 -1
  162. package/lib/documents/artifacts/store.js +0 -169
  163. package/lib/documents/artifacts/store.js.map +0 -1
  164. package/lib/documents/capabilities.js +0 -93
  165. package/lib/documents/capabilities.js.map +0 -1
  166. package/lib/documents/config.js +0 -302
  167. package/lib/documents/config.js.map +0 -1
  168. package/lib/documents/defaults.js +0 -78
  169. package/lib/documents/defaults.js.map +0 -1
  170. package/lib/documents/errors.js +0 -101
  171. package/lib/documents/errors.js.map +0 -1
  172. package/lib/documents/index.js +0 -80
  173. package/lib/documents/index.js.map +0 -1
  174. package/lib/documents/inspect/facts.js +0 -161
  175. package/lib/documents/inspect/facts.js.map +0 -1
  176. package/lib/documents/inspect/zip.js +0 -108
  177. package/lib/documents/inspect/zip.js.map +0 -1
  178. package/lib/documents/markdown/directives.js +0 -135
  179. package/lib/documents/markdown/directives.js.map +0 -1
  180. package/lib/documents/markdown/frontmatter.js +0 -35
  181. package/lib/documents/markdown/frontmatter.js.map +0 -1
  182. package/lib/documents/markdown/normalize.js +0 -113
  183. package/lib/documents/markdown/normalize.js.map +0 -1
  184. package/lib/documents/orchestrator/assets.js +0 -243
  185. package/lib/documents/orchestrator/assets.js.map +0 -1
  186. package/lib/documents/orchestrator/convert-document.js +0 -186
  187. package/lib/documents/orchestrator/convert-document.js.map +0 -1
  188. package/lib/documents/orchestrator/create-document.js +0 -292
  189. package/lib/documents/orchestrator/create-document.js.map +0 -1
  190. package/lib/documents/orchestrator/extract-document.js +0 -162
  191. package/lib/documents/orchestrator/extract-document.js.map +0 -1
  192. package/lib/documents/orchestrator/inspect-document.js +0 -89
  193. package/lib/documents/orchestrator/inspect-document.js.map +0 -1
  194. package/lib/documents/orchestrator/runtime-deps.js +0 -59
  195. package/lib/documents/orchestrator/runtime-deps.js.map +0 -1
  196. package/lib/documents/orchestrator/scope.js +0 -132
  197. package/lib/documents/orchestrator/scope.js.map +0 -1
  198. package/lib/documents/providers/docling.js +0 -247
  199. package/lib/documents/providers/docling.js.map +0 -1
  200. package/lib/documents/providers/libreoffice.js +0 -130
  201. package/lib/documents/providers/libreoffice.js.map +0 -1
  202. package/lib/documents/providers/markitdown.js +0 -89
  203. package/lib/documents/providers/markitdown.js.map +0 -1
  204. package/lib/documents/providers/pandoc.js +0 -161
  205. package/lib/documents/providers/pandoc.js.map +0 -1
  206. package/lib/documents/providers/process.js +0 -164
  207. package/lib/documents/providers/process.js.map +0 -1
  208. package/lib/documents/providers/registry.js +0 -152
  209. package/lib/documents/providers/registry.js.map +0 -1
  210. package/lib/documents/providers/shared.js +0 -75
  211. package/lib/documents/providers/shared.js.map +0 -1
  212. package/lib/documents/runtime.js +0 -114
  213. package/lib/documents/runtime.js.map +0 -1
  214. package/lib/documents/security/file-types.js +0 -188
  215. package/lib/documents/security/file-types.js.map +0 -1
  216. package/lib/documents/security/limits.js +0 -78
  217. package/lib/documents/security/limits.js.map +0 -1
  218. package/lib/documents/security/mime.js +0 -43
  219. package/lib/documents/security/mime.js.map +0 -1
  220. package/lib/documents/security/paths.js +0 -133
  221. package/lib/documents/security/paths.js.map +0 -1
  222. package/lib/documents/templates/registry.js +0 -147
  223. package/lib/documents/templates/registry.js.map +0 -1
  224. package/lib/documents/templates/resolver.js +0 -59
  225. package/lib/documents/templates/resolver.js.map +0 -1
  226. package/lib/documents/tools/convert.js +0 -125
  227. package/lib/documents/tools/convert.js.map +0 -1
  228. package/lib/documents/tools/create.js +0 -187
  229. package/lib/documents/tools/create.js.map +0 -1
  230. package/lib/documents/tools/index.js +0 -41
  231. package/lib/documents/tools/index.js.map +0 -1
  232. package/lib/documents/tools/inspect.js +0 -135
  233. package/lib/documents/tools/inspect.js.map +0 -1
  234. package/lib/documents/tools/shared.js +0 -88
  235. package/lib/documents/tools/shared.js.map +0 -1
  236. package/lib/documents/tools/to-markdown.js +0 -125
  237. package/lib/documents/tools/to-markdown.js.map +0 -1
  238. package/lib/documents/types.js +0 -12
  239. package/lib/documents/types.js.map +0 -1
  240. package/lib/types/client/settings/sections/documents.d.ts +0 -13
  241. package/lib/types/documents/artifacts/ids.d.ts +0 -14
  242. package/lib/types/documents/artifacts/manifest.d.ts +0 -32
  243. package/lib/types/documents/artifacts/store.d.ts +0 -67
  244. package/lib/types/documents/capabilities.d.ts +0 -32
  245. package/lib/types/documents/config.d.ts +0 -27
  246. package/lib/types/documents/defaults.d.ts +0 -161
  247. package/lib/types/documents/errors.d.ts +0 -42
  248. package/lib/types/documents/index.d.ts +0 -63
  249. package/lib/types/documents/inspect/facts.d.ts +0 -43
  250. package/lib/types/documents/inspect/zip.d.ts +0 -28
  251. package/lib/types/documents/markdown/directives.d.ts +0 -39
  252. package/lib/types/documents/markdown/frontmatter.d.ts +0 -15
  253. package/lib/types/documents/markdown/normalize.d.ts +0 -30
  254. package/lib/types/documents/orchestrator/assets.d.ts +0 -55
  255. package/lib/types/documents/orchestrator/convert-document.d.ts +0 -25
  256. package/lib/types/documents/orchestrator/create-document.d.ts +0 -18
  257. package/lib/types/documents/orchestrator/extract-document.d.ts +0 -24
  258. package/lib/types/documents/orchestrator/inspect-document.d.ts +0 -12
  259. package/lib/types/documents/orchestrator/runtime-deps.d.ts +0 -43
  260. package/lib/types/documents/orchestrator/scope.d.ts +0 -52
  261. package/lib/types/documents/providers/docling.d.ts +0 -54
  262. package/lib/types/documents/providers/libreoffice.d.ts +0 -40
  263. package/lib/types/documents/providers/markitdown.d.ts +0 -28
  264. package/lib/types/documents/providers/pandoc.d.ts +0 -42
  265. package/lib/types/documents/providers/process.d.ts +0 -54
  266. package/lib/types/documents/providers/registry.d.ts +0 -68
  267. package/lib/types/documents/providers/shared.d.ts +0 -27
  268. package/lib/types/documents/runtime.d.ts +0 -59
  269. package/lib/types/documents/security/file-types.d.ts +0 -39
  270. package/lib/types/documents/security/limits.d.ts +0 -24
  271. package/lib/types/documents/security/mime.d.ts +0 -13
  272. package/lib/types/documents/security/paths.d.ts +0 -38
  273. package/lib/types/documents/templates/registry.d.ts +0 -50
  274. package/lib/types/documents/templates/resolver.d.ts +0 -30
  275. package/lib/types/documents/tools/convert.d.ts +0 -9
  276. package/lib/types/documents/tools/create.d.ts +0 -14
  277. package/lib/types/documents/tools/index.d.ts +0 -33
  278. package/lib/types/documents/tools/inspect.d.ts +0 -9
  279. package/lib/types/documents/tools/shared.d.ts +0 -77
  280. package/lib/types/documents/tools/to-markdown.d.ts +0 -12
  281. package/lib/types/documents/types.d.ts +0 -294
@@ -0,0 +1,485 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdirSync, readFileSync, renameSync, statSync, writeFileSync, } from "node:fs";
3
+ import path from "node:path";
4
+ /**
5
+ * The durable quality file: user feedback, reviewer results, the manual review
6
+ * queue and the administrative audit trail.
7
+ *
8
+ * It is deliberately separate from the capability policy file: role
9
+ * configuration is a deployment artifact an operator may replace wholesale,
10
+ * while feedback and reviews are user data that must survive such a reset.
11
+ */
12
+ export const QA_FEEDBACK_RATINGS = [
13
+ "positive",
14
+ "negative",
15
+ ];
16
+ export const QA_FEEDBACK_REASONS = [
17
+ "incorrect",
18
+ "instruction_not_followed",
19
+ "missing_information",
20
+ "outdated_information",
21
+ "tool_issue",
22
+ "too_verbose",
23
+ "too_short",
24
+ "other",
25
+ ];
26
+ export const QA_QUALITY_ISSUES = [
27
+ "answer.incorrect",
28
+ "answer.incomplete",
29
+ "answer.hallucination",
30
+ "answer.request_not_followed",
31
+ "answer.poor_formatting",
32
+ "answer.communication",
33
+ "context.missing_conversation",
34
+ "context.missing_knowledge",
35
+ "context.outdated_knowledge",
36
+ "tool.wrong_selection",
37
+ "tool.should_have_been_used",
38
+ "tool.bad_arguments",
39
+ "tool.failure",
40
+ "tool.unavailable",
41
+ "skill.missing",
42
+ "skill.wrong",
43
+ "skill.not_followed",
44
+ "skill.prompt_policy",
45
+ "access.missing_capability",
46
+ "access.excessive_capability",
47
+ "other",
48
+ ];
49
+ export const QA_QUALITY_SEVERITIES = [
50
+ "minor",
51
+ "major",
52
+ "critical",
53
+ ];
54
+ export const QA_REMEDIATION_TARGETS = [
55
+ "prompt",
56
+ "skill",
57
+ "tool",
58
+ "knowledge",
59
+ "role",
60
+ "model",
61
+ "product_ux",
62
+ "user_misunderstanding",
63
+ "unknown",
64
+ ];
65
+ const REVIEW_STATUSES = ["reviewed", "needs_followup"];
66
+ const AUDIT_ACTIONS = [
67
+ "user.created",
68
+ "user.updated",
69
+ "user.enabled",
70
+ "user.disabled",
71
+ "authorization.changed",
72
+ "subrole.assignment.changed",
73
+ "subrole.created",
74
+ "subrole.updated",
75
+ "subrole.deleted",
76
+ "common_capabilities.updated",
77
+ "conversation.reviewed",
78
+ "review.updated",
79
+ "review.queued",
80
+ "admin.settings.updated",
81
+ ];
82
+ /**
83
+ * Retention caps. A long-lived deployment must not grow its quality file
84
+ * without bound; the oldest rows fall off first and every list is newest-first,
85
+ * so a cap only ever hides ancient history. Configurable `admin.retentionDays`
86
+ * (spec §44) belongs to the deployment's own storage lifecycle and is a
87
+ * follow-up.
88
+ */
89
+ const MAX_FEEDBACK = 20_000;
90
+ const MAX_REVIEWS = 5_000;
91
+ const MAX_QUEUE = 2_000;
92
+ const MAX_AUDIT = 5_000;
93
+ const MAX_COMMENT_LENGTH = 2_000;
94
+ const MAX_NOTE_LENGTH = 4_000;
95
+ const MAX_ACTION_LENGTH = 2_000;
96
+ const MAX_ID_LENGTH = 200;
97
+ const MAX_SNAPSHOT_LENGTH = 20_000;
98
+ export function defaultQualityFilePath() {
99
+ const home = process.env.DSH_HOME?.trim();
100
+ return path.join(home !== undefined && home !== "" ? home : process.cwd(), "qa-quality.json");
101
+ }
102
+ function isRecord(value) {
103
+ return typeof value === "object" && value !== null && !Array.isArray(value);
104
+ }
105
+ function requiredText(value, label, max) {
106
+ if (typeof value !== "string") {
107
+ throw new TypeError(`${label} must be a string`);
108
+ }
109
+ const trimmed = value.trim();
110
+ if (trimmed === "")
111
+ throw new TypeError(`${label} must not be empty`);
112
+ if (trimmed.length > max) {
113
+ throw new TypeError(`${label} must be at most ${max} characters`);
114
+ }
115
+ return trimmed;
116
+ }
117
+ function optionalText(value, label, max) {
118
+ if (value === undefined || value === null)
119
+ return undefined;
120
+ if (typeof value !== "string") {
121
+ throw new TypeError(`${label} must be a string`);
122
+ }
123
+ const trimmed = value.trim();
124
+ if (trimmed === "")
125
+ return undefined;
126
+ if (trimmed.length > max) {
127
+ throw new TypeError(`${label} must be at most ${max} characters`);
128
+ }
129
+ return trimmed;
130
+ }
131
+ function oneOf(value, allowed, label) {
132
+ if (typeof value !== "string" || !allowed.includes(value)) {
133
+ throw new TypeError(`${label} must be one of ${allowed.join(", ")}`);
134
+ }
135
+ return value;
136
+ }
137
+ function listOf(value, allowed, label) {
138
+ if (value === undefined || value === null)
139
+ return Object.freeze([]);
140
+ if (!Array.isArray(value))
141
+ throw new TypeError(`${label} must be an array`);
142
+ return Object.freeze([
143
+ ...new Set(value.map((entry) => oneOf(entry, allowed, label))),
144
+ ]);
145
+ }
146
+ function stamp(filePath) {
147
+ const stat = statSync(filePath);
148
+ return { mtimeMs: stat.mtimeMs, size: stat.size };
149
+ }
150
+ function same(left, right) {
151
+ return left?.mtimeMs === right.mtimeMs && left.size === right.size;
152
+ }
153
+ function emptyFile() {
154
+ return { version: 1, feedback: [], reviews: [], queue: [], audit: [] };
155
+ }
156
+ /** Identity of one rating: a user rates one message once. */
157
+ function feedbackKey(conversationId, messageId, userId) {
158
+ return `${conversationId}\u0000${messageId}\u0000${userId}`;
159
+ }
160
+ function asArray(value) {
161
+ return Array.isArray(value) ? value : [];
162
+ }
163
+ /**
164
+ * Atomic, externally reloadable store for the quality layer. Writes are
165
+ * synchronous and persisted with a temp file plus rename, matching the accounts
166
+ * and capability files: LAN scale keeps this trivial, and a reload probe keeps
167
+ * a second process's write visible.
168
+ *
169
+ * Rows are re-validated on read rather than trusted: a hand-edited file cannot
170
+ * inject a record the writers would have refused. A malformed row is reported
171
+ * instead of dropped — writes are atomic, so it can only mean someone edited
172
+ * the file, and silently discarding a user's record would hide that.
173
+ */
174
+ export class QaQualityStore {
175
+ filePath;
176
+ file;
177
+ fileStamp;
178
+ constructor(filePath = defaultQualityFilePath()) {
179
+ this.filePath = filePath;
180
+ this.file = this.load();
181
+ }
182
+ // -------------------------------------------------------------------------
183
+ // Feedback
184
+ // -------------------------------------------------------------------------
185
+ /**
186
+ * Record or replace one user's rating of one message. Re-rating the same
187
+ * message overwrites in place rather than appending: a reviewer reads the
188
+ * user's current verdict, and the first-seen time stays with it.
189
+ */
190
+ rateFeedback(input, feedback) {
191
+ this.reload();
192
+ const conversationId = requiredText(input.conversationId, "conversationId", MAX_ID_LENGTH);
193
+ const messageId = requiredText(input.messageId, "messageId", MAX_ID_LENGTH);
194
+ const rating = oneOf(feedback.rating, QA_FEEDBACK_RATINGS, "rating");
195
+ const reasons = listOf(feedback.reasons, QA_FEEDBACK_REASONS, "reasons");
196
+ const comment = optionalText(feedback.comment, "comment", MAX_COMMENT_LENGTH);
197
+ const key = feedbackKey(conversationId, messageId, input.userId);
198
+ const existing = this.file.feedback.find((row) => feedbackKey(row.conversationId, row.messageId, row.userId) === key);
199
+ const now = new Date().toISOString();
200
+ const record = Object.freeze({
201
+ id: existing?.id ?? randomUUID(),
202
+ conversationId,
203
+ messageId,
204
+ userId: input.userId,
205
+ rating,
206
+ ...(reasons.length === 0 ? {} : { reasons }),
207
+ ...(comment === undefined ? {} : { comment }),
208
+ createdAt: existing?.createdAt ?? now,
209
+ ...(existing === undefined ? {} : { updatedAt: now }),
210
+ });
211
+ this.persist({
212
+ ...this.file,
213
+ feedback: [
214
+ ...this.file.feedback.filter((row) => feedbackKey(row.conversationId, row.messageId, row.userId) !== key),
215
+ record,
216
+ ].slice(-MAX_FEEDBACK),
217
+ });
218
+ return record;
219
+ }
220
+ allFeedback() {
221
+ this.reload();
222
+ return this.file.feedback;
223
+ }
224
+ /** Ratings of one conversation, newest first. */
225
+ feedbackOfConversation(conversationId) {
226
+ this.reload();
227
+ return this.file.feedback
228
+ .filter((row) => row.conversationId === conversationId)
229
+ .sort((left, right) => right.createdAt.localeCompare(left.createdAt));
230
+ }
231
+ /** One exact rating, for the viewer's per-message thumbs state. */
232
+ feedbackOf(conversationId, messageId, userId) {
233
+ this.reload();
234
+ const key = feedbackKey(conversationId, messageId, userId);
235
+ return this.file.feedback.find((row) => feedbackKey(row.conversationId, row.messageId, row.userId) === key);
236
+ }
237
+ // -------------------------------------------------------------------------
238
+ // Reviews
239
+ // -------------------------------------------------------------------------
240
+ /** Save a reviewer's result, replacing that reviewer's earlier verdict. */
241
+ saveReview(reviewerId, input) {
242
+ this.reload();
243
+ const conversationId = requiredText(input.conversationId, "conversationId", MAX_ID_LENGTH);
244
+ const messageId = optionalText(input.messageId, "messageId", MAX_ID_LENGTH);
245
+ const notes = optionalText(input.notes, "notes", MAX_NOTE_LENGTH);
246
+ const suggestedAction = optionalText(input.suggestedAction, "suggestedAction", MAX_ACTION_LENGTH);
247
+ const existing = this.file.reviews.find((row) => row.conversationId === conversationId &&
248
+ row.reviewerId === reviewerId &&
249
+ row.messageId === messageId);
250
+ const now = new Date().toISOString();
251
+ const review = Object.freeze({
252
+ id: existing?.id ?? randomUUID(),
253
+ conversationId,
254
+ ...(messageId === undefined ? {} : { messageId }),
255
+ reviewerId,
256
+ status: oneOf(input.status, REVIEW_STATUSES, "status"),
257
+ issues: listOf(input.issues, QA_QUALITY_ISSUES, "issues"),
258
+ severity: oneOf(input.severity, QA_QUALITY_SEVERITIES, "severity"),
259
+ ...(notes === undefined ? {} : { notes }),
260
+ ...(input.target === undefined
261
+ ? {}
262
+ : {
263
+ target: oneOf(input.target, QA_REMEDIATION_TARGETS, "target"),
264
+ }),
265
+ ...(suggestedAction === undefined ? {} : { suggestedAction }),
266
+ createdAt: existing?.createdAt ?? now,
267
+ ...(existing === undefined ? {} : { updatedAt: now }),
268
+ });
269
+ this.persist({
270
+ ...this.file,
271
+ reviews: [
272
+ ...this.file.reviews.filter((row) => row.id !== review.id),
273
+ review,
274
+ ].slice(-MAX_REVIEWS),
275
+ });
276
+ return { review, created: existing === undefined };
277
+ }
278
+ allReviews() {
279
+ this.reload();
280
+ return this.file.reviews;
281
+ }
282
+ reviewsOfConversation(conversationId) {
283
+ this.reload();
284
+ return this.file.reviews
285
+ .filter((row) => row.conversationId === conversationId)
286
+ .sort((left, right) => right.createdAt.localeCompare(left.createdAt));
287
+ }
288
+ // -------------------------------------------------------------------------
289
+ // Manual review queue
290
+ // -------------------------------------------------------------------------
291
+ /** Park one conversation for review; re-parking the same target is a no-op. */
292
+ enqueueReview(userId, conversationId, messageId) {
293
+ this.reload();
294
+ const conversation = requiredText(conversationId, "conversationId", MAX_ID_LENGTH);
295
+ const message = optionalText(messageId, "messageId", MAX_ID_LENGTH);
296
+ const existing = this.file.queue.find((row) => row.conversationId === conversation && row.messageId === message);
297
+ if (existing !== undefined)
298
+ return existing;
299
+ const entry = Object.freeze({
300
+ conversationId: conversation,
301
+ ...(message === undefined ? {} : { messageId: message }),
302
+ userId,
303
+ createdAt: new Date().toISOString(),
304
+ });
305
+ this.persist({
306
+ ...this.file,
307
+ queue: [...this.file.queue, entry].slice(-MAX_QUEUE),
308
+ });
309
+ return entry;
310
+ }
311
+ /** Drop a manual queue entry once a reviewer has answered it. */
312
+ dequeueReview(conversationId, messageId) {
313
+ this.reload();
314
+ const remaining = this.file.queue.filter((row) => !(row.conversationId === conversationId && row.messageId === messageId));
315
+ if (remaining.length === this.file.queue.length)
316
+ return false;
317
+ this.persist({ ...this.file, queue: remaining });
318
+ return true;
319
+ }
320
+ manualQueue() {
321
+ this.reload();
322
+ return this.file.queue;
323
+ }
324
+ // -------------------------------------------------------------------------
325
+ // Administrative audit
326
+ // -------------------------------------------------------------------------
327
+ /** Append one administrative action to the audit trail. */
328
+ appendAudit(input) {
329
+ this.reload();
330
+ const targetType = optionalText(input.targetType, "targetType", 64);
331
+ const targetId = optionalText(input.targetId, "targetId", MAX_ID_LENGTH);
332
+ const record = Object.freeze({
333
+ id: randomUUID(),
334
+ timestamp: new Date().toISOString(),
335
+ actorId: input.actorId,
336
+ action: oneOf(input.action, AUDIT_ACTIONS, "action"),
337
+ ...(targetType === undefined ? {} : { targetType }),
338
+ ...(targetId === undefined ? {} : { targetId }),
339
+ ...(input.before === undefined
340
+ ? {}
341
+ : { before: this.snapshot(input.before) }),
342
+ ...(input.after === undefined
343
+ ? {}
344
+ : { after: this.snapshot(input.after) }),
345
+ });
346
+ this.persist({
347
+ ...this.file,
348
+ audit: [...this.file.audit, record].slice(-MAX_AUDIT),
349
+ });
350
+ return record;
351
+ }
352
+ auditEvents() {
353
+ this.reload();
354
+ return this.file.audit;
355
+ }
356
+ /** Serialize one before/after value, refusing what no reader could use. */
357
+ snapshot(value) {
358
+ const serialized = JSON.stringify(value);
359
+ if (serialized === undefined)
360
+ return "null";
361
+ if (serialized.length > MAX_SNAPSHOT_LENGTH) {
362
+ return JSON.stringify({ truncated: true });
363
+ }
364
+ return serialized;
365
+ }
366
+ // -------------------------------------------------------------------------
367
+ // Persistence
368
+ // -------------------------------------------------------------------------
369
+ reload() {
370
+ let current;
371
+ try {
372
+ current = stamp(this.filePath);
373
+ }
374
+ catch {
375
+ return;
376
+ }
377
+ if (same(this.fileStamp, current))
378
+ return;
379
+ this.file = this.load();
380
+ }
381
+ load() {
382
+ try {
383
+ const parsed = JSON.parse(readFileSync(this.filePath, "utf8"));
384
+ if (!isRecord(parsed) || parsed.version !== 1) {
385
+ throw new TypeError("unrecognized QA quality file");
386
+ }
387
+ this.fileStamp = stamp(this.filePath);
388
+ return {
389
+ version: 1,
390
+ feedback: Object.freeze(asArray(parsed.feedback).map(restoreFeedback)),
391
+ reviews: Object.freeze(asArray(parsed.reviews).map(restoreReview)),
392
+ queue: Object.freeze(asArray(parsed.queue).map(restoreQueueEntry)),
393
+ audit: Object.freeze(asArray(parsed.audit).map(restoreAuditEvent)),
394
+ };
395
+ }
396
+ catch (error) {
397
+ if (error.code !== "ENOENT")
398
+ throw error;
399
+ const created = emptyFile();
400
+ this.persist(created);
401
+ return created;
402
+ }
403
+ }
404
+ persist(file) {
405
+ mkdirSync(path.dirname(this.filePath), { recursive: true });
406
+ const temporary = `${this.filePath}.${process.pid}.${randomUUID()}.tmp`;
407
+ writeFileSync(temporary, `${JSON.stringify(file, null, 2)}\n`, "utf8");
408
+ renameSync(temporary, this.filePath);
409
+ this.file = file;
410
+ this.fileStamp = stamp(this.filePath);
411
+ }
412
+ }
413
+ function row(value, label) {
414
+ if (!isRecord(value))
415
+ throw new TypeError(`${label} must be an object`);
416
+ return value;
417
+ }
418
+ function restoreFeedback(value) {
419
+ const source = row(value, "feedback");
420
+ const reasons = listOf(source.reasons, QA_FEEDBACK_REASONS, "reasons");
421
+ const comment = optionalText(source.comment, "comment", MAX_COMMENT_LENGTH);
422
+ const updatedAt = optionalText(source.updatedAt, "updatedAt", 64);
423
+ return Object.freeze({
424
+ id: requiredText(source.id, "id", MAX_ID_LENGTH),
425
+ conversationId: requiredText(source.conversationId, "conversationId", MAX_ID_LENGTH),
426
+ messageId: requiredText(source.messageId, "messageId", MAX_ID_LENGTH),
427
+ userId: requiredText(source.userId, "userId", MAX_ID_LENGTH),
428
+ rating: oneOf(source.rating, QA_FEEDBACK_RATINGS, "rating"),
429
+ ...(reasons.length === 0 ? {} : { reasons }),
430
+ ...(comment === undefined ? {} : { comment }),
431
+ createdAt: requiredText(source.createdAt, "createdAt", 64),
432
+ ...(updatedAt === undefined ? {} : { updatedAt }),
433
+ });
434
+ }
435
+ function restoreReview(value) {
436
+ const source = row(value, "review");
437
+ const messageId = optionalText(source.messageId, "messageId", MAX_ID_LENGTH);
438
+ const notes = optionalText(source.notes, "notes", MAX_NOTE_LENGTH);
439
+ const suggestedAction = optionalText(source.suggestedAction, "suggestedAction", MAX_ACTION_LENGTH);
440
+ const updatedAt = optionalText(source.updatedAt, "updatedAt", 64);
441
+ return Object.freeze({
442
+ id: requiredText(source.id, "id", MAX_ID_LENGTH),
443
+ conversationId: requiredText(source.conversationId, "conversationId", MAX_ID_LENGTH),
444
+ ...(messageId === undefined ? {} : { messageId }),
445
+ reviewerId: requiredText(source.reviewerId, "reviewerId", MAX_ID_LENGTH),
446
+ status: oneOf(source.status, REVIEW_STATUSES, "status"),
447
+ issues: listOf(source.issues, QA_QUALITY_ISSUES, "issues"),
448
+ severity: oneOf(source.severity, QA_QUALITY_SEVERITIES, "severity"),
449
+ ...(notes === undefined ? {} : { notes }),
450
+ ...(source.target === undefined
451
+ ? {}
452
+ : { target: oneOf(source.target, QA_REMEDIATION_TARGETS, "target") }),
453
+ ...(suggestedAction === undefined ? {} : { suggestedAction }),
454
+ createdAt: requiredText(source.createdAt, "createdAt", 64),
455
+ ...(updatedAt === undefined ? {} : { updatedAt }),
456
+ });
457
+ }
458
+ function restoreQueueEntry(value) {
459
+ const source = row(value, "review queue row");
460
+ const messageId = optionalText(source.messageId, "messageId", MAX_ID_LENGTH);
461
+ return Object.freeze({
462
+ conversationId: requiredText(source.conversationId, "conversationId", MAX_ID_LENGTH),
463
+ ...(messageId === undefined ? {} : { messageId }),
464
+ userId: requiredText(source.userId, "userId", MAX_ID_LENGTH),
465
+ createdAt: requiredText(source.createdAt, "createdAt", 64),
466
+ });
467
+ }
468
+ function restoreAuditEvent(value) {
469
+ const source = row(value, "audit event");
470
+ const targetType = optionalText(source.targetType, "targetType", 64);
471
+ const targetId = optionalText(source.targetId, "targetId", MAX_ID_LENGTH);
472
+ const before = optionalText(source.before, "before", MAX_SNAPSHOT_LENGTH);
473
+ const after = optionalText(source.after, "after", MAX_SNAPSHOT_LENGTH);
474
+ return Object.freeze({
475
+ id: requiredText(source.id, "id", MAX_ID_LENGTH),
476
+ timestamp: requiredText(source.timestamp, "timestamp", 64),
477
+ actorId: requiredText(source.actorId, "actorId", MAX_ID_LENGTH),
478
+ action: oneOf(source.action, AUDIT_ACTIONS, "action"),
479
+ ...(targetType === undefined ? {} : { targetType }),
480
+ ...(targetId === undefined ? {} : { targetId }),
481
+ ...(before === undefined ? {} : { before }),
482
+ ...(after === undefined ? {} : { after }),
483
+ });
484
+ }
485
+ //# sourceMappingURL=quality-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-store.js","sourceRoot":"","sources":["../../src/admin/quality-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,SAAS,EACT,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,IAAI,MAAM,WAAW,CAAC;AAe7B;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAgC;IAC9D,UAAU;IACV,UAAU;CACX,CAAC;AACF,MAAM,CAAC,MAAM,mBAAmB,GAAgC;IAC9D,WAAW;IACX,0BAA0B;IAC1B,qBAAqB;IACrB,sBAAsB;IACtB,YAAY;IACZ,aAAa;IACb,WAAW;IACX,OAAO;CACR,CAAC;AACF,MAAM,CAAC,MAAM,iBAAiB,GAAkC;IAC9D,kBAAkB;IAClB,mBAAmB;IACnB,sBAAsB;IACtB,6BAA6B;IAC7B,wBAAwB;IACxB,sBAAsB;IACtB,8BAA8B;IAC9B,2BAA2B;IAC3B,4BAA4B;IAC5B,sBAAsB;IACtB,4BAA4B;IAC5B,oBAAoB;IACpB,cAAc;IACd,kBAAkB;IAClB,eAAe;IACf,aAAa;IACb,oBAAoB;IACpB,qBAAqB;IACrB,2BAA2B;IAC3B,6BAA6B;IAC7B,OAAO;CACR,CAAC;AACF,MAAM,CAAC,MAAM,qBAAqB,GAAiC;IACjE,OAAO;IACP,OAAO;IACP,UAAU;CACX,CAAC;AACF,MAAM,CAAC,MAAM,sBAAsB,GAAmC;IACpE,QAAQ;IACR,OAAO;IACP,MAAM;IACN,WAAW;IACX,MAAM;IACN,OAAO;IACP,YAAY;IACZ,uBAAuB;IACvB,SAAS;CACV,CAAC;AACF,MAAM,eAAe,GAAG,CAAC,UAAU,EAAE,gBAAgB,CAAU,CAAC;AAChE,MAAM,aAAa,GAAkC;IACnD,cAAc;IACd,cAAc;IACd,cAAc;IACd,eAAe;IACf,uBAAuB;IACvB,4BAA4B;IAC5B,iBAAiB;IACjB,iBAAiB;IACjB,iBAAiB;IACjB,6BAA6B;IAC7B,uBAAuB;IACvB,gBAAgB;IAChB,eAAe;IACf,wBAAwB;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,YAAY,GAAG,MAAM,CAAC;AAC5B,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,SAAS,GAAG,KAAK,CAAC;AACxB,MAAM,SAAS,GAAG,KAAK,CAAC;AACxB,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACjC,MAAM,eAAe,GAAG,KAAK,CAAC;AAC9B,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAChC,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAuBnC,MAAM,UAAU,sBAAsB;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1C,OAAO,IAAI,CAAC,IAAI,CACd,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EACxD,iBAAiB,CAClB,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,YAAY,CAAC,KAAc,EAAE,KAAa,EAAE,GAAW;IAC9D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,mBAAmB,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,KAAK,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,oBAAoB,CAAC,CAAC;IACtE,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACzB,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,oBAAoB,GAAG,aAAa,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,YAAY,CACnB,KAAc,EACd,KAAa,EACb,GAAW;IAEX,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,mBAAmB,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACzB,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,oBAAoB,GAAG,aAAa,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,KAAK,CACZ,KAAc,EACd,OAAqB,EACrB,KAAa;IAEb,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAU,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,mBAAmB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC;AAED,SAAS,MAAM,CACb,KAAc,EACd,OAAqB,EACrB,KAAa;IAEb,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,mBAAmB,CAAC,CAAC;IAC5E,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;KAC/D,CAAC,CAAC;AACL,CAAC;AAED,SAAS,KAAK,CAAC,QAAgB;IAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,IAAI,CAAC,IAAuB,EAAE,KAAY;IACjD,OAAO,IAAI,EAAE,OAAO,KAAK,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC;AACrE,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AACzE,CAAC;AAED,6DAA6D;AAC7D,SAAS,WAAW,CAClB,cAAsB,EACtB,SAAiB,EACjB,MAAc;IAEd,OAAO,GAAG,cAAc,SAAS,SAAS,SAAS,MAAM,EAAE,CAAC;AAC9D,CAAC;AAED,SAAS,OAAO,CAAC,KAAc;IAC7B,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,OAAO,cAAc;IAIJ,QAAQ;IAHrB,IAAI,CAAmB;IACvB,SAAS,CAAoB;IAErC,YAAqB,QAAQ,GAAW,sBAAsB,EAAE;wBAA3C,QAAQ;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAED,4EAA4E;IAC5E,WAAW;IACX,4EAA4E;IAE5E;;;;OAIG;IACH,YAAY,CACV,KAIC,EACD,QAAgC;QAEhC,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,cAAc,GAAG,YAAY,CACjC,KAAK,CAAC,cAAc,EACpB,gBAAgB,EAChB,aAAa,CACd,CAAC;QACF,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,EAAE,QAAQ,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,EAAE,SAAS,CAAC,CAAC;QACzE,MAAM,OAAO,GAAG,YAAY,CAC1B,QAAQ,CAAC,OAAO,EAChB,SAAS,EACT,kBAAkB,CACnB,CAAC;QACF,MAAM,GAAG,GAAG,WAAW,CAAC,cAAc,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CACtC,CAAC,GAAG,EAAE,EAAE,CACN,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CACrE,CAAC;QACF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,MAAM,GAAsB,MAAM,CAAC,MAAM,CAAC;YAC9C,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,UAAU,EAAE;YAChC,cAAc;YACd,SAAS;YACT,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM;YACN,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;YAC5C,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;YAC7C,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,GAAG;YACrC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;SACtD,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC;YACX,GAAG,IAAI,CAAC,IAAI;YACZ,QAAQ,EAAE;gBACR,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAC1B,CAAC,GAAG,EAAE,EAAE,CACN,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CACrE;gBACD,MAAM;aACP,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC;SACvB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,WAAW;QACT,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAED,iDAAiD;IACjD,sBAAsB,CAAC,cAAsB;QAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ;aACtB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,cAAc,KAAK,cAAc,CAAC;aACtD,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,mEAAmE;IACnE,UAAU,CACR,cAAsB,EACtB,SAAiB,EACjB,MAAc;QAEd,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,WAAW,CAAC,cAAc,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAC5B,CAAC,GAAG,EAAE,EAAE,CACN,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CACrE,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,UAAU;IACV,4EAA4E;IAE5E,2EAA2E;IAC3E,UAAU,CACR,UAAkB,EAClB,KAAgC;QAEhC,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,cAAc,GAAG,YAAY,CACjC,KAAK,CAAC,cAAc,EACpB,gBAAgB,EAChB,aAAa,CACd,CAAC;QACF,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;QAC5E,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC;QAClE,MAAM,eAAe,GAAG,YAAY,CAClC,KAAK,CAAC,eAAe,EACrB,iBAAiB,EACjB,iBAAiB,CAClB,CAAC;QACF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CACrC,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,CAAC,cAAc,KAAK,cAAc;YACrC,GAAG,CAAC,UAAU,KAAK,UAAU;YAC7B,GAAG,CAAC,SAAS,KAAK,SAAS,CAC9B,CAAC;QACF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,MAAM,GAAyB,MAAM,CAAC,MAAM,CAAC;YACjD,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,UAAU,EAAE;YAChC,cAAc;YACd,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;YACjD,UAAU;YACV,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,eAAe,EAAE,QAAQ,CAAC;YACtD,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,iBAAiB,EAAE,QAAQ,CAAC;YACzD,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,qBAAqB,EAAE,UAAU,CAAC;YAClE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;YACzC,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS;gBAC5B,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,sBAAsB,EAAE,QAAQ,CAAC;iBAC9D,CAAC;YACN,GAAG,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC;YAC7D,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,GAAG;YACrC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;SACtD,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC;YACX,GAAG,IAAI,CAAC,IAAI;YACZ,OAAO,EAAE;gBACP,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;gBAC1D,MAAM;aACP,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC;SACtB,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,KAAK,SAAS,EAAE,CAAC;IACrD,CAAC;IAED,UAAU;QACR,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED,qBAAqB,CACnB,cAAsB;QAEtB,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO;aACrB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,cAAc,KAAK,cAAc,CAAC;aACtD,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,4EAA4E;IAC5E,sBAAsB;IACtB,4EAA4E;IAE5E,+EAA+E;IAC/E,aAAa,CACX,MAAc,EACd,cAAsB,EACtB,SAAkB;QAElB,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,YAAY,GAAG,YAAY,CAC/B,cAAc,EACd,gBAAgB,EAChB,aAAa,CACd,CAAC;QACF,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CACnC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,cAAc,KAAK,YAAY,IAAI,GAAG,CAAC,SAAS,KAAK,OAAO,CAC1E,CAAC;QACF,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,QAAQ,CAAC;QAC5C,MAAM,KAAK,GAAuB,MAAM,CAAC,MAAM,CAAC;YAC9C,cAAc,EAAE,YAAY;YAC5B,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;YACxD,MAAM;YACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC;YACX,GAAG,IAAI,CAAC,IAAI;YACZ,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC;SACrD,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC;IAED,iEAAiE;IACjE,aAAa,CAAC,cAAsB,EAAE,SAAkB;QACtD,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CACtC,CAAC,GAAG,EAAE,EAAE,CACN,CAAC,CAAC,GAAG,CAAC,cAAc,KAAK,cAAc,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAC1E,CAAC;QACF,IAAI,SAAS,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC9D,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,WAAW;QACT,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,4EAA4E;IAC5E,uBAAuB;IACvB,4EAA4E;IAE5E,2DAA2D;IAC3D,WAAW,CAAC,KAOX;QACC,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;QACzE,MAAM,MAAM,GAAsB,MAAM,CAAC,MAAM,CAAC;YAC9C,EAAE,EAAE,UAAU,EAAE;YAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC;YACpD,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;YACnD,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;YAC/C,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS;gBAC5B,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5C,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS;gBAC3B,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;SAC3C,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC;YACX,GAAG,IAAI,CAAC,IAAI;YACZ,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC;SACtD,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,WAAW;QACT,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,2EAA2E;IACnE,QAAQ,CAAC,KAAc;QAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,UAAU,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QAC5C,IAAI,UAAU,CAAC,MAAM,GAAG,mBAAmB,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,4EAA4E;IAC5E,cAAc;IACd,4EAA4E;IAEpE,MAAM;QACZ,IAAI,OAAc,CAAC;QACnB,IAAI,CAAC;YACH,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC;YAAE,OAAO;QAC1C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAEO,IAAI;QACV,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAY,CAAC;YAC1E,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;gBAC9C,MAAM,IAAI,SAAS,CAAC,8BAA8B,CAAC,CAAC;YACtD,CAAC;YACD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,OAAO;gBACL,OAAO,EAAE,CAAC;gBACV,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;gBACtE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBAClE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAClE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;aACnE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;YACpE,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACtB,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,IAAsB;QACpC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,MAAM,CAAC;QACxE,aAAa,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvE,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;CACF;AAED,SAAS,GAAG,CAAC,KAAc,EAAE,KAAa;IACxC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,oBAAoB,CAAC,CAAC;IACxE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,mBAAmB,EAAE,SAAS,CAAC,CAAC;IACvE,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,kBAAkB,CAAC,CAAC;IAC5E,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC;QAChD,cAAc,EAAE,YAAY,CAC1B,MAAM,CAAC,cAAc,EACrB,gBAAgB,EAChB,aAAa,CACd;QACD,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,aAAa,CAAC;QACrE,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAC;QAC5D,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,EAAE,QAAQ,CAAC;QAC3D,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;QAC5C,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;QAC7C,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC;QAC1D,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;KAClD,CAAC,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC;IACnE,MAAM,eAAe,GAAG,YAAY,CAClC,MAAM,CAAC,eAAe,EACtB,iBAAiB,EACjB,iBAAiB,CAClB,CAAC;IACF,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC;QAChD,cAAc,EAAE,YAAY,CAC1B,MAAM,CAAC,cAAc,EACrB,gBAAgB,EAChB,aAAa,CACd;QACD,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;QACjD,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC;QACxE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,QAAQ,CAAC;QACvD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,QAAQ,CAAC;QAC1D,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,qBAAqB,EAAE,UAAU,CAAC;QACnE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACzC,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS;YAC7B,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,EAAE,QAAQ,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC;QAC7D,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC;QAC1D,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;KAClD,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;IAC7E,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,cAAc,EAAE,YAAY,CAC1B,MAAM,CAAC,cAAc,EACrB,gBAAgB,EAChB,aAAa,CACd;QACD,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;QACjD,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAC;QAC5D,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC;KAC3D,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,UAAU,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;IACvE,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC;QAChD,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC;QAC1D,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,aAAa,CAAC;QAC/D,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC;QACrD,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;QACnD,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;QAC/C,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3C,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;KAC1C,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The review queue is derived, never stored as its own list: every entry is a
3
+ * signal that still exists — an unanswered negative rating, a deliberate
4
+ * "send to review", a failed tool call — plus the review that answers it. That
5
+ * is what keeps the queue honest when a review is edited or a rating changed.
6
+ *
7
+ * The one exception is the manual entry, which is a reviewer's own act and has
8
+ * no other record; it lives in the quality store.
9
+ */
10
+ /** Reasons that point at a broken answer rather than at user preference. */
11
+ const HIGH_PRIORITY_REASONS = new Set([
12
+ "incorrect",
13
+ "instruction_not_followed",
14
+ "missing_information",
15
+ "outdated_information",
16
+ "tool_issue",
17
+ ]);
18
+ function statusOf(reviews, conversationId, messageId) {
19
+ const covering = reviews.filter((row) => row.conversationId === conversationId &&
20
+ (messageId === undefined ||
21
+ row.messageId === undefined ||
22
+ row.messageId === messageId));
23
+ if (covering.length === 0)
24
+ return { status: "unreviewed", review: undefined };
25
+ const followUp = covering.find((row) => row.status === "needs_followup");
26
+ if (followUp !== undefined)
27
+ return { status: "needs_followup", review: followUp };
28
+ const newest = [...covering].sort((left, right) => right.createdAt.localeCompare(left.createdAt))[0];
29
+ return { status: "reviewed", review: newest };
30
+ }
31
+ function priorityOf(reason, feedback) {
32
+ if (reason === "negative_feedback" && feedback !== undefined) {
33
+ return (feedback.reasons ?? []).some((value) => HIGH_PRIORITY_REASONS.has(value))
34
+ ? "high"
35
+ : "normal";
36
+ }
37
+ // An auto-derived tool failure is a lead, not a verdict; a human decides
38
+ // whether it matters by looking at the conversation.
39
+ return reason === "tool_failure" ? "low" : "normal";
40
+ }
41
+ const PRIORITY_ORDER = {
42
+ high: 0,
43
+ normal: 1,
44
+ low: 2,
45
+ };
46
+ /**
47
+ * Build queue rows, newest signal first within a priority band. A conversation
48
+ * reached by several signals appears once per answered target, so a reviewer
49
+ * can see that the same chat was rated down twice.
50
+ */
51
+ export function deriveQueue({ feedback, reviews, manual, failures = [], }) {
52
+ const items = [];
53
+ for (const row of feedback) {
54
+ if (row.rating !== "negative")
55
+ continue;
56
+ const { status, review } = statusOf(reviews, row.conversationId, row.messageId);
57
+ items.push({
58
+ conversationId: row.conversationId,
59
+ messageId: row.messageId,
60
+ reason: "negative_feedback",
61
+ priority: priorityOf("negative_feedback", row),
62
+ status,
63
+ raisedAt: row.createdAt,
64
+ feedbackId: row.id,
65
+ ...(review === undefined
66
+ ? {}
67
+ : { reviewId: review.id, reviewerId: review.reviewerId }),
68
+ });
69
+ }
70
+ for (const entry of manual) {
71
+ const { status, review } = statusOf(reviews, entry.conversationId, entry.messageId);
72
+ items.push({
73
+ conversationId: entry.conversationId,
74
+ ...(entry.messageId === undefined ? {} : { messageId: entry.messageId }),
75
+ reason: "manual",
76
+ priority: priorityOf("manual", undefined),
77
+ status,
78
+ raisedAt: entry.createdAt,
79
+ ...(review === undefined
80
+ ? {}
81
+ : { reviewId: review.id, reviewerId: review.reviewerId }),
82
+ });
83
+ }
84
+ for (const failure of failures) {
85
+ const { status, review } = statusOf(reviews, failure.conversationId, failure.messageId);
86
+ items.push({
87
+ conversationId: failure.conversationId,
88
+ ...(failure.messageId === undefined
89
+ ? {}
90
+ : { messageId: failure.messageId }),
91
+ reason: "tool_failure",
92
+ priority: priorityOf("tool_failure", undefined),
93
+ status,
94
+ raisedAt: failure.at,
95
+ ...(review === undefined
96
+ ? {}
97
+ : { reviewId: review.id, reviewerId: review.reviewerId }),
98
+ });
99
+ }
100
+ return Object.freeze(items.sort((left, right) => {
101
+ const byPriority = PRIORITY_ORDER[left.priority] - PRIORITY_ORDER[right.priority];
102
+ if (byPriority !== 0)
103
+ return byPriority;
104
+ return right.raisedAt.localeCompare(left.raisedAt);
105
+ }));
106
+ }
107
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/admin/queue.ts"],"names":[],"mappings":"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"}